Są to tak zwane operatory powłoki i tak, jest ich więcej. Przedstawię krótki przegląd najczęstszych wśród dwóch głównych klas, operatorów sterujących i operatorów przekierowujących , oraz ich działania w odniesieniu do powłoki bash.
;
: Wykona jedno polecenie po zakończeniu, niezależnie od wyniku pierwszego.
command1 ; command2
Pierwszy command1
jest uruchamiany na pierwszym planie, a po jego zakończeniu command2
będzie uruchamiany.
Znak nowej linii, który nie jest literałem ciągu lub po określonych słowach kluczowych, nie jest równoważny operatorowi średnika. Lista ;
rozdzielonych prostych poleceń jest wciąż listą - tak jak w parserze powłoki musi nadal czytać proste polecenia, które ;
poprzedzają rozdzielone proste polecenie przed wykonaniem, podczas gdy nowy wiersz może wyznaczyć całą listę poleceń - lub listę list. Różnica jest subtelna, ale skomplikowana: biorąc pod uwagę, że powłoka nie ma wcześniejszej konieczności odczytu danych po nowej linii, nowa linia oznacza punkt, w którym powłoka może zacząć oceniać proste polecenia, które już odczytała, podczas gdy ;
średnik robi nie.
&
: Uruchomi to polecenie w tle, umożliwiając kontynuowanie pracy w tej samej powłoce.
command1 & command2
Tutaj command1
jest uruchamiany w tle i command2
natychmiast uruchamia się na pierwszym planie, nie czekając na command1
wyjście.
Nowa linia po command1
jest opcjonalna.
&&
: Służy do budowania list ORAZ, pozwala uruchomić jedno polecenie tylko wtedy, gdy inne zakończyło się pomyślnie.
command1 && command2
Tutaj command2
uruchomi się po command1
zakończeniu i tylko wtedy, gdy się command1
powiedzie (jeśli kod wyjścia wynosił 0). Oba polecenia są uruchamiane na pierwszym planie.
To polecenie można również zapisać
if command1
then command2
else false
fi
lub po prostu, if command1; then command2; fi
jeśli status zwrotu jest ignorowany.
||
: Służy do budowania list LUB, pozwala uruchomić jedno polecenie tylko wtedy, gdy inne zakończyło się niepowodzeniem.
command1 || command2
Tutaj command2
będzie działać tylko w przypadku command1
niepowodzenia (jeśli zwróci status wyjścia inny niż 0). Oba polecenia są uruchamiane na pierwszym planie.
To polecenie można również zapisać
if command1
then true
else command2
fi
lub w skrócie if ! command1; then command2; fi
.
Zauważ, że &&
i ||
są lewostronne; patrz Pierwszeństwo operatorów logicznych powłoki &&, || po więcej informacji.
!
: To słowo zastrzeżone, które działa jak operator „nie” (ale musi mieć ogranicznik), używane do zanegowania zwracanego statusu polecenia - zwróć 0, jeśli polecenie zwraca stan niezerowy, zwróć 1, jeśli zwróci status 0 Również logiczne NIE dla test
narzędzia.
! command1
[ ! a = a ]
I prawdziwy operator NOT w wyrażeniach arytmetycznych:
$ echo $((!0)) $((!23))
1 0
Pozwalają one kontrolować dane wejściowe i wyjściowe poleceń. Mogą pojawiać się w dowolnym miejscu w ramach prostego polecenia lub mogą następować po poleceniu. Przekierowania są przetwarzane w kolejności, w jakiej się pojawiają, od lewej do prawej.
<
: Daje dane wejściowe do polecenia.
command < file.txt
Powyższe zostanie wykonane command
na podstawie zawartości file.txt
.
<>
: tak samo jak powyżej, ale plik jest otwarty w trybie odczytu + zapisu zamiast tylko do odczytu :
command <> file.txt
Jeśli plik nie istnieje, zostanie utworzony.
Ten operator jest rzadko używany, ponieważ polecenia na ogół odczytują tylko ze standardowego wejścia, choć może się przydać w wielu konkretnych sytuacjach .
>
: Kieruje wyjście polecenia do pliku.
command > out.txt
Powyższe spowoduje zapisanie wyniku command
jako out.txt
. Jeśli plik istnieje, jego zawartość zostanie zastąpiona, a jeśli nie istnieje, zostanie utworzony.
Ten operator jest również często używany do wyboru, czy coś ma zostać wydrukowane na standardowy błąd, czy na standardowe wyjście :
command >out.txt 2>error.txt
W powyższym przykładzie >
przekieruje standardowe wyjście i 2>
przekieruje standardowy błąd. Dane wyjściowe można również przekierowywać za pomocą, 1>
ale ponieważ jest to ustawienie domyślne, 1
zwykle jest pomijane i zapisywane po prostu jako >
.
Tak więc, aby uruchomić command
na file.txt
i zapisać jego wyjście w out.txt
oraz wszelkie komunikaty o błędach w error.txt
jakich można uruchomić:
command < file.txt > out.txt 2> error.txt
>|
: Robi to samo co >
, ale zastąpi cel, nawet jeśli powłoka została skonfigurowana tak, aby odmawiać zastępowania (za pomocą set -C
lub set -o noclobber
).
command >| out.txt
Jeśli out.txt
istnieje, wynik command
zastąpi jego zawartość. Jeśli nie istnieje, zostanie utworzony.
>>
: Robi to samo >
, z tym wyjątkiem, że jeśli plik docelowy istnieje, nowe dane są dodawane.
command >> out.txt
Jeśli out.txt
istnieje, wynik command
zostanie dołączony do niego, po tym, co już w nim jest. Jeśli nie istnieje, zostanie utworzony.
&>
, >&
, >>&
I &>>
: (bez standardowego). Przekieruj zarówno standardowy błąd, jak i standardowe wyjście, odpowiednio zamieniając lub dołączając.
command &> out.txt
Zarówno standardowy błąd, jak i standardowe wyjście command
zostaną zapisane out.txt
, nadpisując jego zawartość lub tworząc, jeśli nie istnieje.
command &>> out.txt
Jak wyżej, z tym wyjątkiem, że jeśli out.txt
istnieje, to wynik i błąd command
zostaną do niego dołączone.
&>
Wariant pochodzi bash
, natomiast >&
wariant pochodzi z csh (lat wcześniej). Oba są w konflikcie z innymi operatorami powłok POSIX i nie powinny być używane w przenośnych sh
skryptach.
<<
: Dokument tutaj. Jest często używany do drukowania ciągów wieloliniowych.
command << WORD
Text
WORD
Tutaj command
zajmie wszystko, dopóki nie znajdzie następnego wystąpienia WORD
, Text
w powyższym przykładzie, jako danych wejściowych. Chociaż WORD
jest często EoF
lub jego odmianami, może być dowolnym ciągiem alfanumerycznym (i nie tylko). Kiedy WORD
jest cytowany, tekst w tym dokumencie jest traktowany dosłownie i nie są wykonywane żadne rozwinięcia (na przykład na zmiennych). Jeśli nie jest cytowany, zmienne zostaną rozwinięte. Aby uzyskać więcej informacji, zobacz instrukcję bash .
Jeśli chcesz potokować wyjście command << WORD ... WORD
bezpośrednio do innego polecenia lub poleceń, musisz umieścić potok w tej samej linii, ponieważ << WORD
nie możesz umieścić go po słowie kończącym lub w wierszu następującym po nim. Na przykład:
command << WORD | command2 | command3...
Text
WORD
<<<
: Ciągi tutaj, podobne do dokumentów tutaj, ale przeznaczone dla jednej linii. Istnieją one tylko w porcie Unix lub rc (skąd pochodzi), zsh, niektórych implementacjach ksh, yash i bash.
command <<< WORD
Cokolwiek jest podane jako WORD
jest rozwinięte, a jego wartość jest przekazywana jako dane wejściowe command
. Jest to często używane do przekazywania zawartości zmiennych jako danych wejściowych do polecenia. Na przykład:
$ foo="bar"
$ sed 's/a/A/' <<< "$foo"
bAr
# as a short-cut for the standard:
$ printf '%s\n' "$foo" | sed 's/a/A/'
bAr
# or
sed 's/a/A/' << EOF
$foo
EOF
Do zamykania lub duplikowania deskryptorów plików można użyć kilku innych operatorów ( >&-
, x>&y
x<&y
). Aby uzyskać szczegółowe informacje na ich temat, zapoznaj się z odpowiednią sekcją podręcznika powłoki ( tutaj na przykład dla bash).
Dotyczy to tylko najpopularniejszych operatorów powłok podobnych do Bourne'a. Niektóre powłoki mają kilka dodatkowych operatorów przekierowań.
bash
. Jest to przygotowywane jako kanoniczne pytania i odpowiedzi, aby zamknąć różne pytania „Co to za dziwne rzeczy robią”, a większość z nich pochodzi od użytkowników bash. Mam nadzieję, że ktoś inny przyłączy się i odpowie za pociski bez basha, ale wyróżnienie tych specyficznych dla basha ma sens. Muszę jednak sprawdzić, nie wiem, które są z mojej głowy.&>
,>>>
i<<<
wszystkie nie są posiksami, podobnie jak odwołanie do nie tylko znaków innych niż alfanum w nazwie tutaj-doc. Ta odpowiedź również bardzo mało mówi o tym , jak działają - na przykład, rozmowa o prostej komendzie i komendzie jest prawie bezużyteczna bez wyjaśnienia, co to jest i jak decyduje powłoka.false
), a kod wyjścia 0 oznacza sukces (nietrue
). Zawsze tak było i jest dość standardowe. Kod wyjścia inny niż 0 oznacza błąd w każdym znanym środowisku.Ostrzeżenie dotyczące „>”
Początkujący w systemie Unix, którzy właśnie dowiedzieli się o przekierowaniu wejścia / wyjścia (
<
i>
) często próbują takich rzeczylub
lub prawie równoważnie
(
grep
,sed
,cut
,sort
, Ispell
są przykłady poleceń, które ludzie będą skłonni do stosowania w konstrukcjach takich jak te.) Użytkownicy są zaskoczeni odkryciem, że te scenariusze spowodować pliku staje się pusta.Niuans, który wydaje się nie wymieniony w drugiej odpowiedzi, znajduje się w pierwszym zdaniu sekcji Przekierowanie bash (1) :
Pierwsze pięć słów powinno być pogrubione, pochylone, podkreślone, powiększone, migające, w kolorze czerwonym i oznaczone ikoną, aby podkreślić fakt, że powłoka dokonuje żądanych przekierowań przed wykonaniem polecenia . I pamiętaj również
W tym przykładzie:
powłoka otwiera
roster
plik do zapisu, obcinając go (tzn. usuwając całą jego zawartość), zanimsort
program zacznie działać. Oczywiście nic nie można zrobić, aby odzyskać dane.Naiwnie można się tego spodziewać
może być lepiej. Ponieważ powłoka obsługuje przekierowania od lewej do prawej, otwiera się
poem
do odczytu (dlatr
standardowego wejścia) przed otwarciem do zapisu (dla standardowego wyjścia). Ale to nie pomaga. Mimo że ta sekwencja operacji daje dwa uchwyty plików, oba wskazują ten sam plik. Gdy powłoka otwiera plik do odczytu, zawartość nadal tam jest, ale nadal są blokowane przed uruchomieniem programu.Co z tym zrobić?
Rozwiązania obejmują:
Sprawdź, czy program, który uruchamiasz, ma swoją własną wewnętrzną możliwość określania, dokąd idzie wyjście. Jest to często wskazywane przez
-o
(lub--output=
) token. W szczególności,jest mniej więcej równoważne z
z wyjątkiem tego, że w pierwszym przypadku
sort
program otwiera plik wyjściowy. I to na tyle, by nie otworzyć pliku wyjściowego mądry dopiero po to odczytać cały plik (ów) wejściowego.Podobnie, przynajmniej niektóre wersje
sed
mają-i
(zmienił i n miejsce) opcji, które mogą być używane do pisania wyjście z powrotem do pliku wejściowego (ponownie, po wszystkie wejścia zostały przeczytane). Redaktorzy lubiąed
/ex
,emacs
,pico
ivi
/vim
pozwalają użytkownikowi edytować plik tekstowy i zapisać edytowany tekst w oryginalnym pliku. Pamiętaj, żeed
(przynajmniej) można używać w sposób nieinteraktywny.vi
ma powiązaną funkcję. Jeśli wpiszesz , zapisze zawartość bufora edycji , odczyta dane wyjściowe i wstawi do bufora (zastępując oryginalną zawartość).:%!command
Entercommand
Proste ale efektywne:
Ma to tę wadę, że jeśli
input_file
jest linkiem, zostanie (prawdopodobnie) zastąpione osobnym plikiem. Ponadto nowy plik będzie własnością użytkownika z domyślnymi zabezpieczeniami. W szczególności niesie to ze sobą ryzyko, że plik będzie czytelny na całym świecie, nawet jeśli oryginałinput_file
nie był.Wariacje:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
co nadal (potencjalnie) pozostawi
temp_file
świat czytelny. Nawet lepiej:cp input_file temp_file && command … temp_file > input_file && rm temp_file
Zachowują one status łącza, właściciela i tryb (ochronę) pliku, potencjalnie kosztem dwa razy więcej operacji we / wy. (Może być konieczne użycie opcji podobnej
-a
lub-p
włączonej,cp
aby nakazać zachowanie atrybutów).command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(podzielone na osobne wiersze tylko dla czytelności) To zachowuje tryb pliku (i, jeśli jesteś rootem, właścicielem), ale czyni go własnością użytkownika (jeśli nie jesteś rootem), i czyni go nowym, osobny plik.
Ten blog (edycja plików w miejscu) sugeruje i wyjaśnia
Wymaga to, aby
command
móc przetwarzać standardowe dane wejściowe (ale prawie wszystkie filtry mogą). Sam blog nazywa to ryzykowną kludge i odradza jego użycie. Spowoduje to również utworzenie nowego, osobnego pliku (niepowiązanego z niczym), będącego własnością użytkownika i posiadającego domyślne uprawnienia.Pakiet moreutils ma polecenie o nazwie
sponge
:Zobacz tę odpowiedź, aby uzyskać więcej informacji.
Oto coś, co mnie całkowicie zaskoczyło: syntaxerror mówi :
W takim przypadku mogą działać następujące elementy:
sort
, czytr
bez-d
lub-s
opcja), można spróbować Zobacz tę odpowiedź i tę odpowiedź, aby uzyskać więcej informacji, w tym wyjaśnienie powyższego, oraz alternatywy, które działają, jeśli twoje polecenie gwarantuje wygenerowanie takiej samej ilości danych wyjściowych, jak jest wejście lub mniej (np.grep
Lubcut
). Te odpowiedzi mają tę zaletę, że nie wymagają żadnej wolnej przestrzeni (lub wymagają bardzo mało). Odpowiedzi powyżej formularza wyraźnie wymagają wystarczającej ilości wolnego miejsca, aby system mógł jednocześnie przechowywać cały (stary) plik i wyjściowy (nowy) plik; nie jest to oczywiście prawda w przypadku większości innych rozwiązań (np. i ). Wyjątek: prawdopodobnie będzie wymagał dużej ilości wolnego miejsca, ponieważcommand … input_file > temp_file && …
sed -i
sponge
sort … | dd …
sort
musi odczytać wszystkie dane wejściowe, zanim będzie mógł zapisać dane wyjściowe, i prawdopodobnie buforuje większość, jeśli nie wszystkie, danych w pliku tymczasowym.dd
odpowiedzią powyżej. Składnia otwiera nazwie pliku na deskryptor pliku zarówno dla wejścia i wyjścia , bez obcinania go - rodzaj połączenia i . Uwaga: Niektóre programy (np. I ) mogą odmówić uruchomienia w tym scenariuszu, ponieważ mogą wykryć, że dane wejściowe i wyjściowe są tym samym plikiem. Zobacz tę odpowiedź w celu omówienia powyższego oraz skrypt, który sprawia, że ta odpowiedź działa, jeśli twoje polecenie gwarantuje wygenerowanie takiej samej ilości danych wyjściowych, jak jest ona wprowadzona lub mniejsza . Ostrzeżenie: nie testowałem skryptu Petera, więc nie rękojmię za to.n<> file
n
n<
n>
cat
grep
Więc jakie było pytanie?
To był popularny temat na U&L; jest rozwiązany w następujących pytaniach:
iconv
zamienić plik wejściowy na przekonwertowane wyjście?shuf file > file
pozostawia pusty plik?sort
polecenie daje mi pusty plik?tr
pliku do pliku… A to nie liczy Super User ani Ask Ubuntu. W tej odpowiedzi umieściłem wiele informacji z odpowiedzi na powyższe pytania, ale nie wszystkie. (Tj., Aby uzyskać więcej informacji, przeczytaj wyżej wymienione pytania i ich odpowiedzi).
PS Nie mam żadnego powiązania z blogiem, który cytowałem powyżej.
źródło
/tmp
.dash
byłaby domyślną powłoką odzyskiwania w Ubuntu i nie tylko nie rozumie<<<
ciągów znaków, ale także otrzymuje anonimowe potoki dla dokumentów<<
hered i nie robi z${TMPDIR:-/tmp}
tym bałaganu cel w ogóle. Zobacz to lub to, aby zobaczyć dema dotyczące obsługi dokumentów tutaj. Także dlaczego ta sama ilość wyników lub mniej ostrzeżeń?dd … conv=notrunc
i1<>
odpowiedzi nigdy nie obcinają pliku wyjściowego, więc jeśli wynik polecenia jest mniejszy niż wejście (np.grep
), na końcu pliku pozostaną pewne bajty oryginału. I, jeśli wynik jest większy niż na wejściu (na przykładcat -n
,nl
lub (potencjalnie)grep -n
), istnieje ryzyko nadpisania starych danych przed już ją przeczytać.Więcej na obserwacje
;
,&
,(
i)
Zauważ, że niektóre polecenia w odpowiedzi terdona mogą być puste. Na przykład możesz powiedzieć
(bez
command2
). Jest to równoważne z(tzn. po prostu działa
command1
na pierwszym planie i czeka na zakończenie. Porównywalnie,(bez
command2
) uruchomi sięcommand1
w tle, a następnie natychmiast wyda kolejny monit powłoki.Natomiast
command1 &&
,command1 ||
icommand1 |
nie ma sensu. Jeśli wpiszesz jeden z nich, powłoka (prawdopodobnie) przyjmie, że polecenie jest kontynuowane w innej linii. Wyświetli monit wtórnej powłoki (kontynuacja), który jest zwykle ustawiony na>
i kontynuuje czytanie. W skrypcie powłoki po prostu odczytuje następny wiersz i dołącza go do tego, co już przeczytał. (Uwaga: to może nie być to, co chcesz się wydarzyć).Uwaga: niektóre wersje niektórych powłok mogą traktować takie niekompletne polecenia jak błędy. W takich przypadkach (lub w rzeczywistości, w każdym przypadku, gdy masz długi polecenie), można wprowadzić odwrotny ukośnik (
\
) na końcu linii, aby powiedzieć skorupę dalej czytać polecenia na innym wierszu:lub
Jak terdon mówi,
(
i)
może być stosowany do poleceń grupowych. Stwierdzenie, że „nie są tak naprawdę istotne” w tej dyskusji, jest dyskusyjne. Niektóre polecenia w odpowiedzi Terdona mogą być grupami poleceń . Na przykład,robi to:
command1
i poczekaj na zakończenie.command2
i poczekaj, aż zakończy się.Jeśli się
command2
powiedzie,command3
i poczekaj na zakończenie.command4
i poczekaj, aż zakończy się.Jeśli się
command2
nie powiedzie, przerwij przetwarzanie wiersza polecenia.Poza nawiasami
|
wiąże się bardzo mocno, więcjest równa
i
&&
i||
wiążą się mocniej niż;
takjest równa
tzn.
command3
będą wykonywane niezależnie od statusu wyjściacommand1
i / lubcommand2
.źródło
;
sam (lub bez poprzedzającego go polecenia) jest błędem składniowym, a nie pustą instrukcją. To; ;
jest błąd. (Często spotykana pułapka dla nowych użytkowników, IMHO). Ponadto:;;
jest specjalnym ogranicznikiem dlacase
instrukcji.;
,&&
,||
,&
, i|
, jeśli są błędy pojawiają się z niczym je poprzedzających. Terdon zwrócił się;;
(krótko) w swojej odpowiedzi.linebreak
tokena w gramatyce powłoki POSIX. Być może więc można śmiało powiedzieć, że wszystkie powłoki zgodne z POSIX je zaakceptują. Podtrzymuję moje oświadczenie jako ogólne wyłączenie odpowiedzialności; jeśli znajdziesz wystarczająco starą powłokę sprzed POSIX, taką jak rzeczywista powłoka Bourne'a lub starsza, wszystkie zakłady są wyłączone.