129

Example:

ls | echo prints nothing ( a blank line, actually ). I'd expect it to print a list of files.

ls | grep 'foo', on the other hand, works as expected ( prints files with 'foo' in their name ).

What I do in these situations is something like: ls | while read OUT; do echo $OUT; done but this is rather cumbersome.

Why does piping work with some commands, but not with others ? How can I circumvent this issue ?

4
  • 3
    What do you expect ls | echo to do? why not simply run ls?
    – theomega
    Commented Sep 16, 2010 at 13:46
  • 19
    I used the simplest example that illustrates my point. I actually encountered this problem when I was trying to make a one-liner that would show git objects in the object store and their type. So, I piped object ID's to git cat-file, but it just didn't work. Apparently, echo has the same behaviour, so I used it as an example. Commented Sep 16, 2010 at 14:10
  • also look at the -n command for xargs, it says how many arguments to put on subcommand. ` ... | xargs -n1 git cat-file` Commented Sep 16, 2010 at 22:05
  • unix.stackexchange.com/a/503197/130767 Commented Mar 10, 2021 at 2:29

5 Answers 5

173

There is a distinction between command line arguments and standard input. A pipe will connect standard output of one process to standard input of another. So

ls | echo

Connects standard output of ls to standard input of echo. Fine right? Well, echo ignores standard input and will dump its command line arguments - which are none in this case to - to its own stdout. The output: nothing at all.

There are a few solutions in this case. One is to use a command that reads stdin and dumps to stdout, such as cat.

ls | cat

Will 'work', depending on what your definition of work is.

But what about the general case. What you really want is to convert stdout of one command to command line args of another. As others have said, xargs is the canonical helper tool in this case, reading the command line args for a command from its stdin and constructing commands to run.

ls | xargs echo

You could also use the substitution command $() to do what you want.

echo $(ls)

Both of these tools are pretty core to shell scripting, you should learn both.

For completeness, as you indicate in the question, the other base way to convert stdin to command line args is the shell's builtin read command. It converts "words" (words as defined by the IFS variable) to a temp variable, which you can use in any command runs.

3
  • 2
    A very helpful an informative answer, thank you ! I'm currently learning bash, and I've seen both xargs and the $(*) notation before, but didn't pay much attention to them. Now I know just how important they are, and will definitely look into them. Commented Sep 16, 2010 at 14:41
  • 2
    xargs may have been what OP was looking for.
    – Heyzeuss
    Commented Dec 16, 2015 at 9:03
  • So I remember: xargs is for those commands that only accept cmd parameters - echo here -, but no std input from commands before - cat can do.
    – Timo
    Commented Apr 15, 2022 at 8:22
24

ls | echo prints just a blank line because echo reads no input; the last command of the pipeline is actually echo that prints nothing but a blank line.

Generally:

a | b

makes sure that the output of a become the input of b. I suggest you to read the Pipelines section of man bash.


If you really want to use ls and echo together here's some (pretty useless) examples:

ls | xargs -L 1 echo
echo `ls`
for i in `ls` ; do echo $i ; done
1
  • Examples may be pretty useless, but it helped me tremendously, in order to find a safe way to remove all folder matching a certain pattern, like so: for i in `find . -iname pattern` ; do rm $i -rf ; done Commented Feb 27, 2023 at 15:47
15

If you want to echo the ls command try:

ls | xargs echo

This will call echo with the output of ls.

2
  • 8
    Or ls | xargs -I {} echo {} if you want it to be called for each line individually Commented Aug 25, 2014 at 8:25
  • @AlexAbdugafarov why do you say "line"? I think it is supposed to be "file/directory" instead. Also if there are spaces in either file or directory, this is not going to get you the correct output. It should be ls | xargs -0 -I {} echo {}
    – Eugene
    Commented Jul 27, 2022 at 8:39
4

Why not simply use:

echo `ls`

Or much safer:

echo "`ls -lrt`"
1
  • 4
    Or even just echo *.
    – Kazark
    Commented Nov 10, 2012 at 3:59
2

This can be achieved in several ways, such as pipe |, STDERR 2>, xargs, or by using the Command Substitution $().

Example of using xargs:

ls | xargs echo
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .