Take the 2-minute tour ×
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.

Per man definition, this command gets the input from a file.

$ command -r FILENAME

Suppose that FILENAME is a file containing a list of filenames, as it was generated using ls > FILENAME.

How can I, instead, feed the command with the result of ls directly? In my head something like this should be possible:

$ ls | command -r

But it doesn't, the output of ls doesn't get hooked as an argument. Output:

Usage: command -r FILENAME
error: -r option requires an argument

How could I obtain the desired effect?

share|improve this question

6 Answers 6

up vote 9 down vote accepted

This is dependent on the command. Some commands that read from a file expect that the file be a regular file, whose size is known in advance, and which can be read from any position and rewinded. This is unlikely if the contents of the file is a list of file names: then the command will probably be content with a pipe which it will just read sequentially from start to finish. There are several ways to feed data via a pipe to a command that expects a file name.

  • Many commands treat - as a special name, meaning to read from standard input rather than opening a file. This is a convention, not an obligation.

    ls | command -r -
    
  • Many unix variants provide special files in /dev that designate the standard descriptors. If /dev/stdin exists, opening it and reading from it is equivalent to reading from standard input; likewise /dev/fd/0 if it exists.

    ls | command -r /dev/stdin
    ls | command -r /dev/fd/0
    
  • If your shell is ksh, bash or zsh, you can make the shell deal with the business of allocating some file descriptor. The main advantage of this method is that it's not tied to standard input, so you can use standard input for something else, and you can use it more than once.

    command -r <(ls)
    
  • If the command expects the name to have a particular form (typically a particular extension), you can try to fool it with a symbolic link.

    ln -s /dev/fd/0 list.foo
    ls | command -r list.foo
    

    Or you can use a named pipe.

    mkfifo list.foo
    ls >list.foo &
    command -r list.foo
    

Note that generating a list of files with ls is problematic because ls tends to mangle file names when they contain unprintable characters. printf '%s\n' * is more reliable — it'll print every byte literally in file names. File names containing newlines will still cause trouble, but that's unavoidable if the command expects a list of file names separated by newlines.

share|improve this answer
    
+1 for enumerating all the possibilities. IMO process substitution is the correct answer for this situation. –  glenn jackman Jul 19 '11 at 22:11

If 'command' is not designed to take its input from 'STDIN', you cannot pipe 'ls' to it.

You could use a temporary file to store the result of 'ls':

ls > tmp
command -r tmp

If for any reason, you cannot store data on disk, you could use a named pipe (fifo):

mkfifo tmp
ls > tmp &
command -r tmp

(Do not forget the '&' after 'ls > tmp' because otherwise it will block until 'command'reads data from the fifo.)

EDIT: sorry for the redundant information about the tmp file, I did not see it the first time I read your question. However, fifo is still a good solution. Could you explain why the tmp file is not suited in your case ?

share|improve this answer
    
First, thanks for your answer. I can live with the tmp file solution, I was just wondering if this could have been done in one step only, for my knowledge and comfort (laziness). –  Guandalino Jul 19 '11 at 20:25

Many commands accept - as a "filename" that means "use the standard input", but this convention is far from universal. Read the man page.

share|improve this answer

It should be:

ls | xargs -n 1 command -r

Edit: for names with blank spaces:

ls | xargs -d '\n' -n 1 command -r
share|improve this answer
    
This could be problematic if command believes it has all the file names it will need on the command line all at once. Some versions of xargs will give command a few file names (10, it seems to me) at a time. Looks like GNU xargs gives everything all at once. –  Bruce Ediger Jul 19 '11 at 20:39

This should work for your purpose: ls | command -r /dev/stdin

share|improve this answer

Actually, the only reliable solution that I know of that can handle all filenames, including those with a newline in them, is:

find . -maxdepth 1 -print0 | xargs -n 1 -0 command -r

The only non allowed character in the filename in this case is the null character, which isn't allowed in filenames anyway.

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.