Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm playing around with the command line interface of mplayer. I'd like to script it in the following way

find /some/path/ -type f | grep -vif blacklist | mplayer -shuffle -playlist -

where blacklist is a text file with artist or song names I'd rather ignore when I have visitors or my son is around (lot's of swear words... :D)

When mplayer encounters the - character, it disables the console input. From the man page:

-noconsolecontrols
          Prevent MPlayer from reading key events from standard input.  
          Useful when reading data from standard input.  This is automatically  
          enabled when - is found on the command line. [snip]

This blocks me from seeking in the file and skipping individual songs. Funnily, this works for videos, because the video window still accepts the usual keyboard inputs.

How can I have the regular console input back? I would like to avoid using a temporary file, although this is of course the easiest solution. -slave and -input don't seem suited and trying -consolecontroles does not work.

share|improve this question
up vote 5 down vote accepted

Feed the input on a file descriptor other than standard input.

find /some/path/ -type f | grep -vif blacklist |
mplayer -shuffle -playlist /dev/fd/3 3<&0 </dev/tty

Explanation of the last line: the data from grep is coming in on standard input, which is file descriptor 0. There's no way to pipe to anywhere but standard input in the shell, but we can do a bit of extra plumbing. First, we connect file descriptor 3 to wherever file descriptor 0 is: 3<&0. Then we connect file descriptor 0 (i.e. standard input) to the terminal: </dev/tty. We tell mplayer to read the playlist from file descriptor 3; mplayer expects a file name, so we pass it /dev/fd/3, which when opened by a process behaves just like file descriptor 3 in that process at that point.

Note that the order of redirections is important, and counterintuitive if you have the wrong intuition. 3<&0 </dev/tty has fd 3 read from where fd 0 read before, and fd 0 read from /dev/tty. </dev/tty 3<&0 would have both fd 0 and fd 3 read from /dev/tty.

share|improve this answer
    
wow, this works! I don't fully understand what's going on, though. – Sebastian Jan 31 '12 at 4:45
    
Read from right to left; /dev/tty is the standard input, 3<&0 redirects the standard input (fd 0) to another one (fd 3) (you might have seen 2&>0 for output redirection) mplayer is told to read the playlist from this other one, i.e /dev/fd/3, which is not stdin and thus doesn't trigger the console input disabling. (Hope I got it right and you don't mind me chipping in, @Gilles.) – sr_ Jan 31 '12 at 8:52

This is kinda overkill, but could still be a viable solution: Use some FUSE filesystem supporting filtering, e.g. FilterFS or rofs-filtered. RevealFS sounds also handy - it is hiding files that lack a user.public extended file attribute (xattr).

Using one of these, you could probably tell mplayer to shuffle all files and thereby keep stdin controls. (Compared to creating two playlists, this is rather much effort, though.)

share|improve this answer
    
thanks for the links, these are interesting pieces of software. – Sebastian Jan 31 '12 at 4:47

As an alternative to explicitly diddling with file descriptors, in Bash you have a convenient way to do pipelines-as-FDs:

mplayer -shuffle -playlist <(find /some/path -type f -not -name '*.foo')

You have both <(COMMAND) (pipe output from command) and >(COMMAND) (pipe output into command) for this kind of purpose. They typically work by using /proc/self/fd/ filenames instead of /dev/fd/ ones, but the effect is the same, just without all the legwork.

Bear in mind, of course, that mplayer will look for non-absolute playlist content files in the same directory as the playlist file; in this case, /proc/self/fd. (The same is true of the /dev/fd solution.) You also have no way to capture exit codes from the command running in <() or >(), without feeding them manually through the command’s stdout and picking through that data on the other side—for everyday command-line use, this doesn’t matter, but for scripting it can be quite bothersome.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.