Uruchamianie wielu poleceń w jednym wierszu powłoki

388

Powiedz, że mam plik /templates/applei chcę

  1. umieść to w dwóch różnych miejscach, a następnie
  2. usuń oryginał.

Tak, /templates/applezostaną skopiowane do /templates/usedAND, /templates/inuse a następnie chciałbym usunąć oryginał.

Czy jest cpto najlepszy sposób, aby to zrobić rm? Czy jest jakiś lepszy sposób?

Chcę to wszystko zrobić w jednym wierszu, więc myślę, że wyglądałoby to tak:

cp /templates/apple /templates/used | cp /templates/apple /templates/inuse | rm /templates/apple

Czy to poprawna składnia?

John Redyns
źródło

Odpowiedzi:

792

Używasz |(potoku), aby skierować wyjście polecenia do innego polecenia. To, czego szukasz, to &&operator, który wykona następną komendę, tylko jeśli poprzednia się powiodła:

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

Lub

cp /templates/apple /templates/used && mv /templates/apple /templates/inuse

Podsumowując (niewyczerpująco) operatory / separatory poleceń bash:

  • |potoki (potoki) standardowe wyjście ( stdout) jednego polecenia do standardowego wejścia innego. Zauważ, że stderrnadal trafia do domyślnego miejsca docelowego, cokolwiek by się nie stało.
  • |&potokuje zarówno jedno, jak stdouti stderrjedno polecenie do standardowego wejścia innego. Bardzo przydatne, dostępne w wersji bash 4 i nowszych.
  • &&wykonuje prawą komendę &&tylko wtedy, gdy poprzednia się powiodła.
  • ||wykonuje tylko prawą komendę ||, poprzednia nie powiodła się.
  • ;wykonuje polecenie po prawej stronie ;zawsze, niezależnie od tego, czy poprzednie polecenie zakończyło się powodzeniem, czy nie. Chyba że set -ewcześniej został wywołany, co powoduje bashbłąd przy błędzie.
Maxim Egorushkin
źródło
6
Pozytywne. Oficjalna dokumentacja gnu.org/software/bash/manual/bash.html#Lists
flow2k
78

Dlaczego nie cpdo lokalizacji 1, a następnie mvdo lokalizacji 2. To zajmuje się „usunięciem” oryginału.

I nie, to nie jest poprawna składnia. |służy do „potoku” wyjścia z jednego programu i przekształcenia go w dane wejściowe dla następnego programu. To, czego chcesz, to ;oddzielenie wielu poleceń.

cp file1 file2 ; cp file1 file3 ; rm file1

Jeśli potrzebujesz, aby poszczególne polecenia MUSI się powieść, zanim będzie można uruchomić następne, użyj &&zamiast tego:

cp file1 file2 && cp file1 file3 && rm file1

W ten sposób, jeśli jedno z cppoleceń nie powiedzie się, rmnie uruchomi się.

Marc B.
źródło
10

Zauważ, że cp A B; rm Ajest dokładnie mv A B. Będzie też szybszy, ponieważ nie musisz kopiować bajtów (zakładając, że miejsce docelowe znajduje się w tym samym systemie plików), po prostu zmień nazwę pliku. Więc chceszcp A B; mv A C

Glenn Jackman
źródło
7

Inną opcją jest pisanie Ctrl+V Ctrl+Jna końcu każdego polecenia.

Przykład (wymienić #z Ctrl+V Ctrl+J):

$ echo 1#
echo 2#
echo 3

Wynik:

1
2
3

Spowoduje to wykonanie poleceń niezależnie od tego, czy poprzednie nie powiodły się.

Taki sam jak: echo 1; echo 2; echo 3

Jeśli chcesz zatrzymać wykonywanie nieudanych poleceń, dodaj &&na końcu każdego wiersza oprócz ostatniego.

Przykład (wymienić #z Ctrl+V Ctrl+J):

$ echo 1 &&#
failed-command &&#
echo 2

Wynik:

1
failed-command: command not found

W zshmożna również użyć Alt+Enterlub Esc+EnterzamiastCtrl+V Ctrl+J

Eyal Levin
źródło
3

Spróbuj tego..

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

Piotr
źródło
2

Używanie rur wydaje mi się dziwne. W każdym razie powinieneś użyć logicznego andoperatora Bash:

$ cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apples

Jeśli cppolecenia nie powiodą się, rmnie zostaną wykonane.

Możesz też stworzyć bardziej rozbudowaną linię poleceń za pomocą forpętli i cmp.

Renaud
źródło