cat a.txt | xargs -I % echo %
W powyższym przykładzie xargs przyjmuje echo %
jako argument polecenia. Ale w niektórych przypadkach potrzebuję wielu poleceń do przetworzenia argumentu zamiast jednego. Na przykład:
cat a.txt | xargs -I % {command1; command2; ... }
Ale xargs nie akceptuje tej formy. Jednym ze znanych mi rozwiązań jest to, że mogę zdefiniować funkcję do zawijania poleceń, ale nie jest to potok, nie wolę tego. Czy jest inne rozwiązanie?
while
tworzyć potoki w pętli, która może zawierać wiele poleceń.Odpowiedzi:
... lub bez bezużytecznego użycia kota :
Aby wyjaśnić niektóre drobniejsze kwestie:
Zastosowanie
"$arg"
zamiast%
(i brak-I
wxargs
linii poleceń) ze względów bezpieczeństwa: przekazywanie danych na tematsh
listy parametru wywołania „S zamiast zastąpienie go do zawartości Uniemożliwia to kodowi, który danych może zawierać (na przykład$(rm -rf ~)
, w celu szczególnie złośliwy przykład) przed wykonaniem jako kod.Podobnie użycie
-d $'\n'
rozszerzenia GNU powoduje,xargs
że każdą linię pliku wejściowego traktuje się jako osobny element danych. Albo to, albo-0
(która spodziewa się wartości NUL zamiast znaków nowej linii) jest konieczne, aby uniemożliwić xargsowi próbowanie zastosowania parsowania typu powłoki (ale niezupełnie kompatybilnego z powłoką) do strumienia, który czyta. (Jeśli nie masz GNU xargs, możesz użyć,tr '\n' '\0' <a.txt | xargs -0 ...
aby uzyskać odczyt zorientowany liniowo bez-d
)._
Jest zastępczy$0
, tak, że inne wartości danych dodawane przezxargs
się$1
i dalej, co okazuje się być domyślny zestaw wartościom jakofor
pętla iteracyjnie.źródło
sh -c
- pamiętaj, że średnik po każdym poleceniu nie jest opcjonalny, nawet jeśli jest to ostatnie polecenie na liście.command1
icommand2
; Później zrozumiałem, że nie są konieczne.}
:sh -c '{ command1; command2; }' -- but it's not required at the end of a command sequence that doesn't use braces:
sh -c 'command1; polecenie2 ''%
znak gdzieś w przekazanym ciągush -c
, to jest to podatne na luki w zabezpieczeniach: nazwa pliku zawierająca$(rm -rf ~)'$(rm -rf ~)'
(i to jest całkowicie legalny podciąg w nazwie pliku na wspólnych systemach plików UNIX!) Spowoduje, że ktoś będzie miał bardzo zły dzień .Dzięki GNU Parallel możesz:
Obejrzyj filmy wprowadzające, aby dowiedzieć się więcej: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Ze względów bezpieczeństwa zaleca się użycie menedżera pakietów do zainstalowania. Ale jeśli nie możesz tego zrobić, możesz użyć tej 10-sekundowej instalacji.
10 sekundowa instalacja spróbuje wykonać pełną instalację; jeśli to się nie powiedzie, instalacja osobista; jeśli to się nie powiedzie, minimalna instalacja.
źródło
To tylko kolejne podejście bez Xargsa i kota:
źródło
IFS
, zignoruje początkowe i końcowe białe spacje w nazwach plików; chyba że dodasz-r
, nazwy plików z dosłownymi ukośnikami odwrotnymi będą ignorowane.xargs
. (Trudno to rozszerzyć, aby zrobić coś podobnego do opcji GNUxargs
'-P<n>
)$ command | while read line; do c1 $line; c2 $line; done
Możesz użyć
{} = zmienna dla każdej linii w pliku tekstowym
źródło
file.txt
zawiera dane$(rm -rf ~)
jako podciąg?Jedną z rzeczy, które robię, jest dodanie do .bashrc / .profile tej funkcji:
wtedy możesz robić takie rzeczy jak
która jest mniej szczegółowa niż xargs lub -exec. Możesz również zmodyfikować funkcję, aby wstawić wartość z odczytu w dowolnym miejscu w komendach do każdego polecenia, jeśli potrzebujesz tego również.
źródło
Wolę styl, który pozwala na tryb pracy na sucho (bez
| sh
):Działa również z rurami:
źródło
-P
opcję ... (Jeśli nie, to najczęściej korzystają-exec
nafind
, ponieważ moje wejścia są przeważnie nazwy plików)Trochę późno na imprezę.
Używam poniższego formatu do kompresji moich katalogów tysiącami małych plików przed migracją. Jeśli nie potrzebujesz pojedynczych cudzysłowów wewnątrz poleceń, powinno działać.
Po pewnych modyfikacjach jestem pewien, że przyda się komuś. Testowane w
Cygwin
(babun)find .
Znajdź tutaj-maxdepth 1
Nie wchodź do katalogów potomnych! -path .
Wyklucz. / Bieżąca ścieżka katalogu-type d
pasuje tylko do katalogów-print0
Oddziel wyniki przez bajty null \ 0| xargs
Potok do xargs Dane-0
wejściowe są oddzielone null bajty-I @@
Symbol zastępczy to @@. Zamień @@ na dane wejściowe.bash -c '...'
Uruchom polecenie Bash{...}
Grupowanie poleceń&&
Wykonaj następne polecenie tylko wtedy, gdy poprzednie polecenie zakończyło się pomyślnie (wyjście 0)Finał
;
jest ważny, inaczej się nie powiedzie.Wynik:
Aktualizacja z lipca 2018 r .:
Jeśli lubisz hacki i zabawę, oto coś ciekawego:
Wynik:
Objaśnienie:
- Utwórz pojedynczy skrypt liniowy i zapisz go w zmiennej
-
xargs
odczytujea.txt
i wykonuje jakobash
skrypt-
@@
upewnia się za każdym razem, gdy przekazywany jest cały wiersz- Umieszczenie
@@
po--
upewnia się, że@@
parametrbash
polecenia pozycyjnego jest brany pod uwagę, a nie jakobash
początekOPTION
, tj. jak-c
sam, co oznaczarun command
--
jest magiczny, działa z wieloma innymi rzeczami, np.ssh
nawetkubectl
źródło
find . -type f -print0|xargs -r0 -n1 -P20 bash -c 'f="{}";ls -l "$f"; gzip -9 "$f"; ls -l "$f.gz"'
(Jest trochę łatwiej przy konwersji pętli)"$@"
to jedyny sposób, aby tego uniknąć ... (-n1
jeśli chcesz ograniczyć liczbę parametrów))--
jest używany przez powłokę, aby powiedzieć, że nie ma już więcej opcji do zaakceptowania. Pozwala to tam się-
po--
zbyt. Możesz uzyskać bardzo interesujący i mylący wynik, jeśli tego nie zrobisz, np.grep -r
Gdy weźmiesz pod uwagę wzorzec-
! Sposób, w jaki to wypowiadasz, nie wyjaśnia tego, ale tak naprawdę nie wyjaśnia, jak to działa. Iirc to kwestia POSIX, ale i tak warto to podkreślić, tak myślę. Tylko coś do rozważenia. I uwielbiam ten bonus btw!To wydaje się być najbezpieczniejszą wersją.
(
-0
Mogą być usunięte itr
zastąpione przekierowania (lub plik można zastąpić null oddzielone plik zamiast). Jest to przede wszystkim tam, ponieważ używam główniexargs
zefind
przy-print0
wyjściu) (To może również być istotna wxargs
wersjach bez-0
rozszerzenia)Jest to bezpieczne, ponieważ podczas wykonywania argumenty przekazują parametry do powłoki jako tablicę. Powłoka (przynajmniej
bash
) przekazałaby je następnie jako niezmienioną tablicę do innych procesów, gdy wszystkie zostaną uzyskane przy użyciu["$@"][1]
Jeśli użyjesz
...| xargs -r0 -I{} bash -c 'f="{}"; command "$f";' ''
, przypisanie nie powiedzie się, jeśli ciąg zawiera podwójne cudzysłowy. Dotyczy to każdego wariantu używającego-i
lub-I
. (Ponieważ jest zamieniany na ciąg znaków, zawsze możesz wstrzykiwać polecenia, wstawiając nieoczekiwane znaki (takie jak cudzysłowy, znaki wsteczne lub znaki dolara) do danych wejściowych)Jeśli polecenia mogą przyjmować tylko jeden parametr na raz:
Lub z nieco mniejszą ilością procesów:
Jeśli masz GNU
xargs
lub inny z-P
rozszerzeniem i chcesz uruchomić 32 procesy równolegle, każdy z nie więcej niż 10 parametrami dla każdego polecenia:Powinno to być odporne na wszelkie znaki specjalne na wejściu. (Jeśli dane wejściowe są rozdzielone zerą.)
tr
Wersja otrzyma nieprawidłowe dane wejściowe, jeśli niektóre wiersze zawierają znaki nowego wiersza, ale jest to nieuniknione w przypadku pliku oddzielonego znakiem nowego wiersza.Pusty pierwszy parametr dla
bash -c
wynika z tego: (Ze strony podręcznikabash
man ) (Dzięki @clacke)źródło
"$@"
bash -c 'command1 "$@"; command2 "$@";' arbitrarytextgoeshere
bash
z-c
bierze pierwszy (po poleceniach) jeden argument, który będzie nazwa procesu, wówczas przyjmuje argumentów pozycyjnych. Spróbujbash -c 'echo "$@" ' 1 2 3 4
i zobacz, co wyjdzie.Innym możliwym rozwiązaniem, które działa dla mnie, jest coś w stylu -
Zwróć uwagę na „bash” na końcu - zakładam, że jest przekazywany jako argv [0] do bash. Bez tej składni pierwszy parametr każdego polecenia zostanie utracony. Może to być dowolne słowo.
Przykład:
źródło
"$@"
, to dzielisz ciągi znaków i rozszerzasz listę argumentów.Mój obecny BKM do tego jest
Szkoda, że używa to perla, który jest mniej prawdopodobne niż bash; ale obsługuje więcej danych wejściowych niż zaakceptowana odpowiedź. (Z zadowoleniem przyjmuję wszechobecną wersję, która nie opiera się na perlu.)
@ Sugestia KeithThompsona dotycząca
jest świetny - chyba że masz znak komentarza powłoki #, w którym to przypadku część pierwszego polecenia i wszystkie drugie polecenie zostaną obcięte.
Hashes # może być dość powszechne, jeśli dane wejściowe pochodzą z listy systemów plików, takich jak ls lub find, a twój edytor tworzy pliki tymczasowe z # w nazwie.
Przykład problemu:
Ups, tutaj jest problem:
Ahh, to lepiej:
źródło
ls | xargs -I % sh -c 'echo 1 "%"; echo 2 "%"'