Jak zastosować polecenie powłoki do każdego wiersza wyniku polecenia?


192

Załóżmy, że mam dane wyjściowe z polecenia (takiego jak ls -1):

a
b
c
d
e
...

Chcę zastosować polecenie (powiedzmy echo) do każdego z nich z kolei. Na przykład

echo a
echo b
echo c
echo d
echo e
...

Jak najłatwiej to zrobić w bash?


3
ls -1może być tutaj przykładem, ale ważne jest, aby pamiętać, że analizowanie wyniku nie jest dobre ls. Zobacz: mywiki.wooledge.org/ParsingLs
codeforester

Odpowiedzi:


217

Jest to prawdopodobnie najłatwiejszy w użyciu xargs. W Twoim przypadku:

ls -1 | xargs -L1 echo

-LFlaga gwarantuje wejście jest prawidłowo odczytać. Ze strony podręcznika użytkownika xargs:

-L number
    Call utility for every number non-empty lines read. 
    A line ending with a space continues to the next non-empty line. [...]

24
lsautomatycznie robi to -1w rurze.
Wstrzymano do odwołania.

5
@Dennis, nie wygląda to tak: ls | xargs -L2 echoi ls -1 | xargs -L2 echodaje dwa różne wyniki. Ten pierwszy jest na jednej linii.
Alex Budovski,

2
@Alex: Dostaję to samo wyjście.
Wstrzymano do odwołania.

6
xargsmoże uruchamiać tylko pliki wykonywalne, a nie funkcje powłoki lub wbudowane polecenia powłoki. W przypadku tego pierwszego najlepszym rozwiązaniem jest prawdopodobnie rozwiązanie z readpętlą.
pabouk

12
Chciałbym, aby ta odpowiedź zawierała wyjaśnienie, po co -L1.
Wyck

164

Możesz użyć podstawowej operacji poprzedzającej w każdej linii:

ls -1 | while read line ; do echo $line ; done

Lub możesz przesłać dane wyjściowe do sed dla bardziej złożonych operacji:

ls -1 | sed 's/^\(.*\)$/echo \1/'

1
Wydaje się, że polecenie sed nie działa: sh: cho: not found a sh: cho: not foundwygląda na to, że eodbija się echem od polecenia sed lub czegoś takiego.
Alex Budovski

+1 za whilepętlę. cmd1 | while read line; do cmd2 $line; done. Lub while read line; do cmd2 $line; done < <(cmd1)który nie tworzy podpowłoki. To jest uproszczona wersja twojego sedpolecenia:sed 's/.*/echo &/'
Wstrzymana do odwołania.

1
@Alex: zmień podwójne cudzysłowy na pojedyncze.
Wstrzymano do odwołania.

5
Cytuj "$line"pętlę while, aby uniknąć podziału słów.
ignis,

3
Spróbuj użyć, read -r lineaby uniknąć readbałaganu ze znakami ucieczki. Na przykład echo '"a \"nested\" quote"' | while read line; do echo "$line"; donedaje "a "nested" quote", który stracił ucieczkę. Jeśli to zrobimy echo '"a \"nested\" quote"' | while read -r line; do echo "$line"; done, otrzymamy "a \"nested\" quote"zgodnie z oczekiwaniami. Zobacz wiki.bash-hackers.org/commands/builtin/read
Warbo

9

Możesz użyć pętli for :

dla pliku w *; robić
   echo „$ file”
Gotowe

Zauważ, że jeśli dane polecenie akceptuje wiele argumentów, wówczas użycie xargs jest prawie zawsze bardziej wydajne, ponieważ wystarczy tylko odrodzić dane narzędzie, a nie wiele razy.


1
Warto opisać prawidłowe / bezpieczne korzystanie z xargs, tj. printf '%s\0' * | xargs -0 ...- w przeciwnym razie jest to dość niebezpieczne z nazwami plików z białymi spacjami, cytatami itp.
Charles Duffy

8

Rzeczywiście można używać sed to zrobić, pod warunkiem, że jest GNU sed.

... | sed 's/match/command \0/e'

Jak to działa:

  1. Dopasuj zamiennie dopasowaniem polecenia
  2. Po podstawieniu wykonaj polecenie
  3. Zamień podstawiony wiersz na polecenie wyjściowe.

Fantastyczny. Zapomniałem umieścić polecenie e na końcu, ale zrobiłem to po zobaczeniu twojej odpowiedzi i zadziałało. Próbowałem dołączyć losowy identyfikator między 1000 a 15000, gdy SED pasuje do linii. cat /logs/lfa/Modified.trace.log.20150904.pw | sed -r 's/^(.*)(\|006\|00032\|)(.*)$/echo "\1\2\3 - ID `shuf -i 999-14999 -n 1`"/e'
sgsi


2

xargs kończy się niepowodzeniem z odwrotnymi ukośnikami, cudzysłowami. To musi być coś podobnego

ls -1 |tr \\n \\0 |xargs -0 -iTHIS echo "THIS is a file."

Opcja xargs -0:

-0, --null
          Input  items are terminated by a null character instead of by whitespace, and the quotes and backslash are
          not special (every character is taken literally).  Disables the end of file string, which is treated  like
          any  other argument.  Useful when input items might contain white space, quote marks, or backslashes.  The
          GNU find -print0 option produces input suitable for this mode.

ls -1kończy elementy znakami nowej linii, więc trtłumaczy je na znaki puste.

To podejście jest około 50 razy wolniejsze niż iteracja ręczna for ...(patrz odpowiedź Michaela Aarona Safyana ) (3,55s vs. 0,066s). Ale w przypadku innych poleceń wejściowych, takich jak lokalizuj, znajdź, odczytuj z pliku ( tr \\n \\0 <file) lub podobnego, musisz pracować w xargsten sposób.


1

Lepszy wynik dla mnie:

ls -1 | xargs -L1 -d "\n" CMD

Lepsze, ale nie idealne. find . -mindepth 1 -maxdepth 1 -print0 | xargs -0 commandzajmie się przypadkami, w których wynik ls -1jest niejednoznaczny; używaj -printf '%P\0'raczej, niż -print0jeśli nie chcesz prowadzić ./na każdym z nich.
Charles Duffy

1

na przykład lubię używać gawk do uruchamiania wielu poleceń na liście

ls -l | gawk '{system("/path/to/cmd.sh "$1)}'

jednak ucieczka uciekających postaci może być nieco owłosiona.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.