19

I dont quite understand how pipes work in bash.

I know that it takes an output from one command as the input in another command.

What an output is I can get because it's what the command prints out to the screen.

But how do I know what input a command will take?

Here is an example I thought would work:

which gem | rm

Unfortunately it didn't.

Which gem prints out /usr/bin/gem so that must be the output right?

I thought that was given to rm so it woud be rm /usr/bin/gem but I was wrong.

So my question is, how do I know what input a command takes?

1
  • 2
    Apart from anything else, rm /usr/bin/gem is a terrible idea. Leave that gem (and the Ruby interpreter it goes with) alone and install your preferred Ruby interpreter (and gem) using rvm: rvm.beginrescueend.com
    – Telemachus
    Aug 21, 2010 at 14:27

4 Answers 4

26

"Input" and "command line arguments" are different things.

rm removes the files provided as arguments.

A pipe redirects the output of the left-hand command to the input of the right-hand command. It does not affect the command line arguments of the program on the right.

To do what you're trying to do, try using xargs to convert standard input to command-line arguments for executing a program. That's its job.

which gem | xargs rm, for example, will remove the gem in your PATH.

14

rm doesn't take input, it takes arguments. These are different. Arguments are the switches and filenames and so forth that you give to a program on the command line to affect its behavior. Input is the data that the program works on. For example, grep takes both input and arguments:

grep "foo" file.txt

There are two arguments there "foo" and file.txt. The input is the contents of file.txt, not the string file.txt itself. Since grep takes input, you can use it with pipes:

cat file.txt | grep "foo"

produces the same output, since cat is taking file.txt as an argument, and producing the contents of file.txt as output. That output is then piped in to grep, giving the same effect as having grep open the file itself, as in the first example.

If you want to use the output of one program as the argument to another, you use backticks:

rm `which gem`

or this alternative (bash-specific) syntax:

rm $(which gem)

Edit: or xargs as another answerer points out. Many ways to skin a cat with a command line.

7
  • It's worth noting that cat file.txt | grep "foo" can be hundreds of times slower than grep "foo" file.txt.
    – Borealid
    Aug 21, 2010 at 3:11
  • 2
    this is the part i dont get. how do i know what is an argument and what is standard input?
    – ajsie
    Aug 21, 2010 at 3:15
  • 10
    @ajsie: If you type it after the program name and before pressing enter, it's an argument. If you type it into the program after it starts running, it's standard input.
    – Borealid
    Aug 21, 2010 at 3:21
  • 1
    Got it! This explained everything. Now I know I can both use the command directly and see if it prompts me (grep) and i could also read the manual (man grep) to see if it uses std input.
    – ajsie
    Aug 21, 2010 at 3:26
  • @ajsie: If you don't want to dive into the manpage, there's also grep --help for a quick overview of the arguments accepted.
    – Borealid
    Aug 21, 2010 at 3:29
3

Check out the man pages of commands you're interested in. These programs will indicate that they read from stdin (try man grep for a popular command that reads stdin).

1
  • I tried man grep | grep 'standard input' and got If no file arguments are specified, the standard input is used. as the last match. 👍 I had to give grep a little taste of its own medicine. 😎
    – ma11hew28
    Sep 24, 2015 at 14:53
2

These are all dangerous to run if you have a directory in your PATH that contains space or if the command name contains space:

rm `which gem`       # Dangerous
rm $(which gem)      # Dangerous
which gem | xargs rm # Dangerous

GNU Parallel https://www.gnu.org/software/parallel/ does not have that problem, so this will work even if you have a directory in your PATH that contains space or if the command name contains space:

which gem | parallel rm
parallel -a <(which bass) rm

Watch the intro video for GNU Parallel: http://www.youtube.com/watch?v=OpaiGYxkSuQ

1
  • rm $(whatever) should give one chills. Always use quotes! I.e. rm "$(whatever)". Unless you mean to delete multiple files, but then xargs -0 or find -delete might be better options (no need to resort to parallel). Feb 1, 2022 at 20:21

You must log in to answer this question.

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