Idiom du jour

gnat on 2002-08-28T04:08:37

Have you let xargs into your life? xargs is designed to get around the shell's limitation of the number of arguments a program can take. xargs takes lines of input and turns them into commandline arguments:

ls -1 | xargs chmod 755
repeatedly runs the chmod command with a bunch of filenames per invocation until all the output of ls is consumed.

But xargs has a fatal flaw. Spaces in filenames screw it up.

So my shell idiom of choice is now something like:

ls -1 | perl -e 'chomp(@args = <>); while (@args) { @a = splice(@args, 0, 50); system("chmod", "755", @args) }'
(though I'd use Perl's built-in chmod rather than shelling out, in this case).

The case that inspired it was fixing the id3 tags on my mp3 files:

find . -name \*.mp3 -print | perl -e 'chomp(@args=<>); while (@args) { @a = splice(@args, 0, 50); system("id3convert", @a) }'
Change 50 to however many arguments per command you want.


Spaces in filenames

pjm on 2002-08-28T06:31:47

I'm probably missing something obvious here, but can't you just throw a backslash before any space in one of the arguments? That is, just use something like:

ls -1 | perl -pe 's/ /\\ /g' | xargs chmod 755

The more usual (and more comprehensive) way 'round this seems to be to use "find" for everything, and then combine find's "-print0" option with the -0 option to xargs. But that doesn't help much with a simple pipe from "ls".


Re:Spaces in filenames

rafael on 2002-08-28T07:20:28

If you have GNU ls, you can use -Q.

ls -Q | xargs chmod 755

If you don't have it, you know the motto : Get New Utilities.

Re:Spaces in filenames

jdavidb on 2002-08-28T13:13:30

+1, informative

Re:Spaces in filenames

oneiron on 2002-08-28T08:49:54

I have been using xargs with space-riddled filenames for many years, as shown by examples below:

find . -print0|xargs -0 chmod 755 (GNU only)
find . -print|sed 's/ /\\ /g'|xargs chmod 755 (works everywhere)

Re:Spaces in filenames

gnat on 2002-08-28T16:25:55

Well bugger, I live and I learn! Thanks to everyone who pointed out print0.

Well, the Perl idiom of sucking a bunch of array elements off at a time still stands, but now I feel SUPERHUMAN with my new-found shell fu.

use.perl to the rescue!