Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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?

share|improve this question

migrated from stackoverflow.com Aug 21 '10 at 20:44

This question came from our site for professional and enthusiast programmers.

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 '10 at 14:27

4 Answers 4

up vote 16 down vote accepted

"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.

share|improve this answer

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.

share|improve this answer
    
It's worth noting that cat file.txt | grep "foo" can be hundreds of times slower than grep "foo" file.txt. –  Borealid Aug 21 '10 at 3:11
1  
this is the part i dont get. how do i know what is an argument and what is standard input? –  ajsie Aug 21 '10 at 3:15
6  
@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 '10 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 '10 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 '10 at 3:29

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).

share|improve this answer

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 http:// 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

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.