Quote:
Originally Posted by jakykong
I hadn't considered using xargs... <snip> 1That's definitely a lot easier to read.
|
I don't know if it's any easier, my example command is a bit more verbose. However, what I find myself doing a lot is using
echo to see what
xargs is doing before committing myself to it. So first I add in the
echo like this:
Code:
find . -maxdepth 1 | grep -v dest_dir | xargs -i echo mv {} ./dest_dir
The above won't actually
mv any files, but will echo out the commands. You can either straight away feed the output to
sh like this:
Code:
find . -maxdepth 1 | grep -v dest_dir | xargs -i echo mv {} ./dest_dir | sh -x
(I tacked on the
-x to the
sh so that I can see each command run such that I can see the command interspersed with any errors that occur in the move). But that isn't very useful in and of itself, but what is useful is maybe doing some sed in between the
xargs and the
sh.
Oh don't get me started (too late!). Let me warn you about "bad" characters in file names: I have a lot of mp3 files with characters such as spaces, single- and double-quotes. I often want to feed them to tools such as
id3v2 to canonicalize the tags. I start out doing something like this:
Code:
find . -name '*.mp3' | xargs -i id3v2 -l {}
which, if you are lucky, gives you a nice error message (xargs on other UNIX's ... well ... maybe not so lucky):
Code:
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
Huh? What's that
-0 about? It's meant to be used with a command that emits records separated with null codes and not newline codes. The
find command by default uses newlines as record separators, but you can change that with the
-print0 option (but then it becomes useful only to commands such as xargs that can slurp in output that contains null bytes as the record separator). Using
find in that way, and changing
xargs to use the
-0 option, yields:
Code:
find . -name '*.mp3' -print0 | xargs -0 -i echo id3v2 -l \"{}\"
Oh, and I wrapped double-quotes around the
{} and backslashed them. The backslashes are to escape the double-quotes from the shell that I'm typing the command into, so that the eventual
shell will not see the single-quotes and get fouled up. And I added the
echo so that I could see the commands before committing to them (like I had mentioned earlier). The resulting output on some of my music that had the single quotes and spaces in them looks like this:
Code:
...
id3v2 -l "./The Cars Greatest Hits/10 Let's Go.mp3"
id3v2 -l "./The Cars Greatest Hits/08 My Best Friend's Girl.mp3"
id3v2 -l "./The Cars Greatest Hits/01 Just What I Needed.mp3"
id3v2 -l "./The Cars-All Mixed Up.mp3"
...
then I can tack on the
sh along with other filtering like this:
Code:
find . -name '*.mp3' -print0 | xargs -0 -i echo id3v2 -l \"{}\" | sh -x | grep '^TIT2'
resulting in some meaningful output (notice the "+" are from the
-x I fed to
sh:
Code:
+ id3v2 -l './The Cars Greatest Hits/10 Let'\''s Go.mp3'
TIT2 (Title/songname/content description): Let's Go
+ id3v2 -l './The Cars Greatest Hits/08 My Best Friend'\''s Girl.mp3'
+ id3v2 -l './The Cars Greatest Hits/01 Just What I Needed.mp3'
TIT2 (Title/songname/content description): My Best Friend's Girl
+ id3v2 -l './The Cars-All Mixed Up.mp3'
TIT2 (Title/songname/content description): Just What I Needed
TIT2 (Title/songname/content description): All Mixed Up
The "+" output lines made it past the final
grep most likely because the
sh command puts those onto
standard error and not onto
standard output. Notice also that the standard error output is not synchronized with standard output, which puzzles some users.
Whew! Ok I'm done now (I think).
bg