Why doesn't process substitution work with VLC playlists?

Why doesn't process substitution work with VLC playlists?

Because vlc is poorly designed in this matter. Worse, it is poorly designed twice:
probably has its reasons* to work in a way that creates the following two disadvantages:

  • inotifywait -m my_ordered_playlist.m3u reveals that upon vlc my_ordered_playlist.m3u the file is opened and read several times. I haven't investigated if there are seeks involved. When you use <(shuf my_ordered_playlist.m3u) vlc gets data piped from shuf and it's able to read it exactly once. Apparently this is not enough. In a perfect world vlc would read data just once and it should be enough.

  • vlc refuses to work with a playlist without extension. In Zsh there is =() syntax similar to <(); the difference is the shell creates a temporary regular file instead of a pipe. Such file can be read multiple times and it's seekable. It seems a good solution to your problem (if you're OK with Zsh), but normally the filename is without the extension, so vlc =(shuf my_ordered_playlist.m3u) still doesn't work.

    But there's a way:

    # in zsh
    TMPSUFFIX=.m3u; vlc =(shuf my_ordered_playlist.m3u)

    Run the commands in a subshell if you want the change to TMPSUFFIX not to affect the main shell.

*The statement "vlc is poorly designed" received a useful comment:

I suspect at least one of the seeks through the file is to determine if the file is ANSI, UTF-8 or UTF-16 (with or without a Byte Order Mark) and then re-scan the file with an appropriate format applied internally. Of course that doesn't stop the fact that VLC is expecting an extension, which isn't that stupid when you consider the number of formats VLC might possibly see... You can't really expect it to scan the file first, and rub it against every internal decoder to see which one works, the action of which would empty the pipe after the first seek and make the data useless again...

An alternative option is to do it in two stages and pass an already shuffled playlist to VLC in a file rather than on the command line.

shuf my_ordered_playlist.m3u > /tmp/random_playlist.m3u && vlc /tmp/random_playlist.m3u

You might be able to even extend it to

shuf my_ordered_playlist.m3u > /tmp/random_playlist.m3u && vlc /tmp/random_playlist.m3u && rm /tmp/random_playlist.m3u 

To clean up after VLC exits.

You could even use a bash alias

alias shuf_vlc="shuf my_ordered_playlist.m3u > /tmp/random_playlist.m3u && vlc /tmp/random_playlist.m3u && rm /tmp/random_playlist.m3u"

and then just run shuf_vlc to shuffle your playlist.

The reason your command doesn't work is because it is still a pipe and subject to the limitations of a pipe.

Limitations of Process Substistution

Process substitution has some limitations:

  • No file seeking: the "files" created are not seekable, which means the process reading or writing to the file cannot perform random access; it must read or write once from start to finish. Programs that explicitly check the type of a file before opening it may refuse to work with process substitution, because the "file" resulting from process substitution is not a regular file.

  • No exit codes: "It is not possible to obtain the exit code of a process substitution command from the shell that created the process substitution."

Depending on the behaviour your are seeing it may be that VLC is seeking through to check for a valid playlist (in order to check UTF-8/16 etc or that the file is constructed properly), but not actually reading the playlist on the first pass. It tries to go back to actually load the files and due to "no file seeking" fails to read the playlist. The first pass effectively empties the pipe that is given a file descriptor and then there is nothing to work with.

Alternatively VLC checks that the file is "real" and able to be seeked and on finding that it cannot simply refuses to open it as it will not be able to parse both forwards and backwards through the file.

Your first two commands are simple and expect nothing more than a readable stream, VLC wants something real that it can hold on to.