2011-10-13 11 views
5

Jak mogę iterować po wszystkich liniach wyprowadzanych przez polecenie za pomocą zsh, bez ustawiania IFS?Jak mogę iterować po wszystkich liniach wyprowadzanych przez polecenie w zsh?

Powodem jest to, że chcę uruchomić polecenie dla każdego pliku wyjściowego za pomocą polecenia, a niektóre z tych plików zawierają spacje.

Eg, biorąc pod uwagę usunięty plik:

foo/bar baz/gamma 

Oznacza to, że pojedynczy katalog 'foo', zawierająca podkatalogu 'bar baz', zawierający plik 'gamma'.

Następnie uruchomiony:

git ls-files --deleted | xargs ls 

zgłosi w tym pliku jest obsługiwany jako dwa pliki: 'foo/bar' oraz '/ baz/gamma'.

Potrzebuję go do obsługi jako jeden plik: "foo/bar baz/gamma".

+0

Czy twój system ma polecenie xargs? – lunixbochs

+0

@lunixboches: Tak, ale nadal nie obsługuje poprawnie linii. – Arafangion

+2

'git ls-files -z | xargs -0 ls' użyje separatorów zerowych (\ 0) zamiast białych znaków – lunixbochs

Odpowiedz

4

Korzystanie tr i możliwość xargs-0, zakładając, że linie nie zawierają \000 (NUL), która jest uzasadniona ze względu na założenie NUL jest jednym ze znaków, które nie mogą pojawić się w nazwach plików:

git ls-files --deleted | tr '\n' '\000' | xargs -0 ls 

okaże linię: foo/bar baz/gamma\n do foo/bar baz/gamma\000 który xargs -0 umie obsłużyć

+0

Nie może być lepiej, dzięki! (I działa też w bash!) – Arafangion

7

Jeśli chcesz uruchomić komendę raz dla wszystkich linii:

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

fparameter expansion flag oznacza podział polecenia na nowe linie. Istnieje bardziej ogólna forma (@s:||:), która dzieli się na dowolny ciąg znaków, taki jak ||. Flaga @ oznacza zachowanie pustych rekordów. Nieco mylące, cała ekspansja musi znajdować się wewnątrz podwójnych cudzysłowów, aby uniknąć rozszczepienia się na wyjściu z , ale wytworzy osobne słowa dla każdego rekordu.

Jeśli chcesz uruchomić komendę dla każdej linii kolei przenośny idiom nie jest szczególnie skomplikowana:

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

Jeśli chcesz uruchomić polecenie jako kilka razy jako limit zezwoleń długość linii poleceń , użyj zargs.

autoload -U zargs 
zargs -- "${(@f)$(git ls-files --deleted)}" -- ls 
+0

Dzięki za to - jest tu dużo użytecznych informacji, ale myślę, że xargs jest jeszcze bardziej wydajny, ponieważ uruchomi jedno polecenie dla każdej grupy plików. (Co jeśli mam tak wiele plików, które nie mieszczą się na liście argumentów?) – Arafangion

+0

@Arafangion 'zargs' jest jak' xargs' (działa jak mało instancji, podczas gdy pasuje do limitu długości linii poleceń), tylko z rozsądny interfejs. – Gilles

+0

Jeszcze lepiej, dzięki. :) Sprawdzę to. – Arafangion

Powiązane problemy