Kiedy jesteś już przy szyi w aligatorach, łatwo zapomnieć, że celem było osuszenie bagna.
- popularne powiedzenie
Pytanie dotyczy echo, a jednak większość dotychczasowych odpowiedzi koncentrowała się na tym, jak wprowadzić set +xpolecenie. Istnieje o wiele prostsze, bardziej bezpośrednie rozwiązanie:
{ echo "Message"; } 2> /dev/null
(Przyznaję, że nie pomyślałbym o tym, { …; } 2> /dev/null
gdybym nie widział tego we wcześniejszych odpowiedziach).
Jest to nieco kłopotliwe, ale jeśli masz blok kolejnych echopoleceń, nie musisz robić tego dla każdego z osobna:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Pamiętaj, że nie potrzebujesz średników, gdy masz nowe znaki.
Możesz zmniejszyć obciążenie związane z pisaniem, używając pomysłu kenorba na/dev/null stałe
otwarcie na niestandardowym deskryptorze pliku (np. 3), a następnie mówienie 2>&3zamiast przez 2> /dev/nullcały czas.
Pierwsze cztery odpowiedzi w chwili pisania tego tekstu wymagają zrobienia czegoś specjalnego (i w większości przypadków kłopotliwego) za
każdym razem, gdy robisz echo. Jeśli naprawdę chcesz, aby wszystkie echo polecenia pomijały ślad wykonania (a dlaczego byś tego nie zrobił?), Możesz to zrobić globalnie, bez mungowania dużej ilości kodu. Po pierwsze zauważyłem, że aliasy nie są śledzone:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Zauważ, że następujące fragmenty skryptu działają, jeśli shebang jest #!/bin/sh, nawet jeśli /bin/shjest linkiem do bash. Ale jeśli shebang jest #!/bin/bash, musisz dodać shopt -s expand_aliasespolecenie, aby aliasy działały w skrypcie.)
Tak więc dla mojej pierwszej sztuczki:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Teraz, kiedy mówimy echo "Message", wzywamy alias, który nie jest śledzony. Alias wyłącza opcję śledzenia, jednocześnie tłumiąc komunikat śledzenia z setpolecenia (przy użyciu techniki przedstawionej najpierw w odpowiedzi użytkownika 5071535 ), a następnie wykonuje rzeczywiste echopolecenie. To pozwala nam uzyskać efekt podobny do odpowiedzi user5071535 bez konieczności edytowania kodu przy każdym echo poleceniu. Pozostawia to jednak tryb śledzenia wyłączony. Nie możemy wstawić a set -xdo aliasu (a przynajmniej niełatwo), ponieważ alias pozwala tylko na zastąpienie łańcucha słowem; żadna część ciągu aliasu nie może zostać wstrzyknięta do polecenia
po argumentach (np "Message".). Na przykład, jeśli skrypt zawiera
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
wynik byłby
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
więc nadal musisz włączyć opcję śledzenia po wyświetleniu komunikatu (komunikatów) - ale tylko raz po każdym bloku kolejnych echopoleceń:
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Byłoby miło , gdybyśmy mogli zrobić set -xautomatykę po echo- i możemy, przy odrobinie więcej sztuczek. Ale zanim to przedstawię, zastanów się nad tym. OP zaczyna się od skryptów wykorzystujących #!/bin/sh -exshebang. W domyśle użytkownik może usunąć xz shebang i mieć skrypt, który działa normalnie, bez śledzenia wykonania. Byłoby miło, gdybyśmy mogli opracować rozwiązanie, które zachowałoby tę właściwość. Kilka pierwszych odpowiedzi tutaj zawodzi tej właściwości, ponieważ echobezwarunkowo włączają śledzenie instrukcji po , bez względu na to, czy była już włączona.
Ta odpowiedź wyraźnie nie rozpoznaje tego problemu, ponieważ zastępuje echodane wyjściowe z danymi wyjściowymi śledzenia; dlatego wszystkie wiadomości znikają, jeśli śledzenie jest wyłączone. Przedstawię teraz rozwiązanie, które warunkowo włącza śledzenie po echoinstrukcji - tylko jeśli była już włączona. Obniżenie tego poziomu do rozwiązania, które bezwarunkowo odwraca śledzenie, jest trywialne i pozostawia się jako ćwiczenie.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-jest lista opcji; konkatenacja liter odpowiadających wszystkim ustawionym opcjom. Na przykład, jeśli ustawione są opcje ei x, to $-będzie mieszanka liter zawierająca ei x. Mój nowy alias (powyżej) zapisuje wartość $-przed wyłączeniem śledzenia. Następnie przy wyłączonym śledzeniu przekazuje kontrolę nad funkcją powłoki. Ta funkcja wykonuje rzeczywistą operację, echo
a następnie sprawdza, czy xopcja została włączona po wywołaniu aliasu. Jeśli opcja była włączona, funkcja ponownie ją włącza; jeśli był wyłączony, funkcja go wyłącza.
Możesz wstawić powyższe siedem wierszy (osiem, jeśli dołączasz an shopt) na początku skryptu, a resztę pozostawić w spokoju.
To by ci pozwoliło
- aby użyć dowolnej z następujących linii shebang:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / sh –x
lub po prostu#! / bin / sh
i powinno działać zgodnie z oczekiwaniami.
- mieć podobny kod
(shebang)
polecenie 1
polecenie 2
polecenie 3
ustaw -x
polecenie 4
polecenie 5
polecenie 6
ustaw + x
polecenie 7
polecenie 8
polecenie 9
i
- Polecenia 4, 5 i 6 będą śledzone - chyba że jedno z nich jest
echo, w takim przypadku będzie wykonywane, ale nie śledzone. (Ale nawet jeśli polecenie 5 jest echo, polecenie 6 nadal będzie śledzone.)
- Polecenia 7, 8 i 9 nie będą śledzone. Nawet jeśli polecenie 8 jest
echo, polecenie 9 nadal nie będzie śledzone.
- Polecenia 1, 2 i 3 będą śledzone (jak 4, 5 i 6) lub nie (jak 7, 8 i 9) w zależności od tego, czy zawiera shebang
x.
PS Odkryłem, że w moim systemie mogę pominąć builtinsłowo kluczowe w środkowej odpowiedzi (tej, dla której jest to tylko alias echo). Nie jest to zaskakujące; bash (1) mówi, że podczas rozwijania aliasu…
… Słowo identyczne z rozwijanym aliasem nie jest rozszerzane po raz drugi. Oznacza to, że jeden może alias lsdo ls -F, na przykład, a bash nie próbuje rekursywnie rozwiń tekst.
Nic dziwnego, że ostatnia odpowiedź (ta z echo_and_restore) kończy się niepowodzeniem, jeśli builtinsłowo kluczowe zostanie pominięte 1 . Ale dziwnie to działa, jeśli usunę builtini zmienię kolejność:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Wydaje się, że powoduje niezdefiniowane zachowanie. widziałem
- nieskończona pętla (prawdopodobnie z powodu nieograniczonej rekurencji),
/dev/null: Bad addresskomunikat o błędzie i
- zrzut rdzenia.
echo +x; echo "$*"; echo -xw aliasie, chciałbym to zobaczyć.