xargs is probably one of the more difficult to understand of the unix command arsenal and of course that just means it’s one of the most useful too.
I discovered a handy trick that I thought was worth a share. Please note there are probably other (better) ways to do this but I did my stackoverflow research and found nothing better.
Using xargs to back-reference command line args even post-sed/grep/etc.
xargs — at least how I’ve most utilized it — is handy for taking some number of lines as input and doing some work per line. It’s hard to be more specific than that as it does so much else.
It literally took me an hour of piecing together random man pages + tips from 11 year olds on stack overflow, but eventually I produced this gem:
This is an example of how to find files matching a certain pattern and rename each of them. It sounds so trivial (and it is) but it demonstrates some cool tricks in an easy concept.
ls | grep 'aaa' | sed 'p;s/aaa/bbb/' | xargs -n2 | xargs -L1 bash -c 'mv $0 $1'Whatsitdo?
> mv file_aaa_1 file_bbb_1
> mv file_aaa_2 file_bbb_2
> mv file_aaa_3 file_bbb_3
Lets break it down:
ls | grep 'aaa' | ...
Find our files matching a certain pattern and pipe them to standard out. You probably knew that.
sed 'p;s/aaa/bbb' | ...
receiving standard in from the previous command. sed (as you’d expect) replaces the input per line with the regex substitution provided and pipes the replaced string to the next command. You probably knew this too. However did you know about the ‘p;’ because I didn’t. ‘p;’ tells sed to precede the replaced string output with a line containing the original input. So you get 2 lines instead of 1. Line1: original input line. Line2: replaced line. Why would you want that? Well in this particular example we need the before and after name of the file to move it. “move file_aaa_1 file_bbb_1".
xargs -n2 | ...
Here’s where xargs becomes our best friend. xargs -n2 takes 2 lines and merges them into 1 delimited by a space. So the output from the sed command gets translated from “file_aaa_1\nfile_bbb1” to “file_aaa_1 file_bbb1”. That’s useful because we want the next xargs command to be able to back-reference the space-delimited args in our bash command.
xargs -L1 bash -c 'mv $0 $1'
The last leg. xargs receives lines of input containing the original filename and the new filename. -L1 tells xargs to process the following command every 1 line (-Ln will process every n lines). The “bash -c” part I’m a little fuzzy on, but I believe tells xargs to run the following bash command. ‘mv $0 $1’ is our command and $0 is the original filename “file_aaa_1” and $1 is the new filename “file_bbb_1”.
I’m sure I got something wrong — let the Unix Guru’s flame begin.