Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I iterate over all the lines output by a command in zsh?

How do I iterate over all the lines output by a command using zsh, without setting IFS?

The reason is that I want to run a command against every file output by a command, and some of these files contain spaces.

Eg, given the deleted file:

foo/bar baz/gamma

That is, a single directory 'foo', containing a sub directory 'bar baz', containing a file 'gamma'.

Then running:

git ls-files --deleted | xargs ls

Will report in that file being handled as two files: 'foo/bar', and '/baz/gamma'.

I need it to handle it as one file: 'foo/bar baz/gamma'.

like image 710
Arafangion Avatar asked Oct 13 '11 06:10

Arafangion


1 Answers

If you want to run the command once for all the lines:

ls "${(@f)$(git ls-files --deleted)}"

The f parameter expansion flag means to split the command's output on newlines. There's a more general form (@s:||:) to split at an arbitrary string like ||. The @ flag means to retain empty records. Somewhat confusingly, the whole expansion needs to be inside double quotes, to avoid IFS splitting on the output of the command substitution, but it will produce separate words for each record.

If you want to run the command for each line in turn, the portable idiom isn't particularly complicated:

git ls-filed --deleted | while IFS= read -r line; do ls $line; done

If you want to run the command as few times as the command line length limit permits, use zargs.

autoload -U zargs
zargs -- "${(@f)$(git ls-files --deleted)}" -- ls
like image 196
Gilles 'SO- stop being evil' Avatar answered Sep 20 '22 10:09

Gilles 'SO- stop being evil'