tags:

views:

126

answers:

6

Lately, I've often found myself wanting to run some command on the output of another command that has output on several lines.

For example, let's say I have a command that returns a number of file paths each on a new line and I'd like to delete all these files.

Is there a command that can help me do this?

+3  A: 

In bash-like shells you can do:

rm `your command`

or

rm $(your command)
Peter Kovacs
This works well until the file names contain spaces, or the list grows too long.
Jonathan Leffler
+7  A: 

It sounds like you're looking for xargs. From the man page:

xargs reads arguments from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines, and executes the command (default is /bin/echo) one or more times with any initial-arguments followed by arguments read from standard input.

So you can do things like:

ls | grep -v '*.cpp' | xargs rm

The above command would delete everything in the current directory except *.cpp files.

Greg Hewgill
+3  A: 

In Windows, CMD:

for /f "usebackq delims=" %i in (`your command`) @del "%i"

Powershell:

your command | Remove-Item
Joey
A: 

try

cat file | while read i; do echo "working on line $i"; done

Although you can have trouble with lines having spaces. I never remember how to fix that. Please note that this command works for every manipulation on a line-by-line basis. Using xargs works only for the example case you asked (and similar cases), but if you can solve your problem with xargs, definitely go for it.

Stefano Borini
You're looking for cut. This would print the first column. If you want to get fancier, check out sed and/or awk.http://www.manpagez.com/man/1/cut/cat file | while read i; do FOO=echo $i | cut -f1; echo $FOO; done(EDIT: moved from answer to comment)
John
+1  A: 
ls | xargs rm

one interesting use (to search a directory for a phrase inside a file)

find /path/to/dir | xargs grep "search text"

That one isn't related, but it shows how xargs works

Alex Gartrell
+1  A: 

Assuming a UNIX-like environment:

To handle spaces in names, use the -0 flag to xargs. With find:

find . -name '*.mp3' -print0 | xargs -0 dosomething

Some other commands have various switches for nul-separated output, usually -0 or -z. If your list is line-oriented, do something like:

cat filelist | tr -s '\012\015' '\000' | xargs -0 dosomething

Which uses tr to translate newlines and linefeeds to nuls, handling UNIX and DOS (and even Mac Classic) line ends and skipping blank lines.

Don't forget that newlines are valid filename characters on most UNIX-like filesystems.

If dosomething is complex, you can use bash functions:

dosomething() {
    while [ -n "$1" ] ; do
        out="$(basename "$1" .mp3).ogg"
        convert "$1" "converted/$out"
        shift
    done
}

export -f dosomething

and invoke xargs like:

cat filelist | tr -s '\012\015' '\000' | xargs -0 bash -c 'dosomething "$@"' --

Note the judicious use of double-quoting to preserve spaces, and that double-quoted strings can be nested inside double-quoted $() eval operators.

Within the function, you can write "$@" to get a properly quoted argument list to pass to a subprocess:

dosomething() {
    command1 preargs "$@" postargs | command2
    command3 "$@"
}

You can also use read to work line-by-line:

cat filelist | while read i ; do something "$i" ; done

but xargs gets you all of the args at once.

Frank Szczerba