Czy istnieje sposób na rurze wyjście z jednej funkcji do drugiej, ale tylko wtedy, gdy jest wyjście?
Czy istnieje sposób na rurze wyjście z jednej funkcji do drugiej, ale tylko wtedy, gdy jest wyjście?
Odpowiedzi:
Poniższa ifnotempty
funkcja potokuje dane wejściowe do polecenia przekazanego jako argument, z wyjątkiem tego, że nic nie robi, jeśli dane wejściowe są puste. Użyj go do rury source --foo
pod sink --bar
pisząc source --foo | pipe_if_not_empty sink --bar
.
pipe_if_not_empty () {
head=$(dd bs=1 count=1 2>/dev/null; echo a)
head=${head%a}
if [ "x$head" != x"" ]; then
{ printf %s "$head"; cat; } | "$@"
fi
}
Uwagi do projektu:
dd
nie czyta więcej niż jeden bajt, który czytał na swoim standardowym wejściu.head -c 1
byłby odpowiednim zamiennikiem dla dd bs=1 count=1 2>/dev/null
systemu Linux.head -n 1
nie byłby odpowiedni, ponieważ head
zwykle buforuje jego dane wejściowe i może czytać więcej niż jedną linię, którą wysyła - a ponieważ odczytuje z potoku, dodatkowe bajty są po prostu tracone.read -r head
a nawet read -r -n 1 head
nie są tu odpowiednie, ponieważ jeśli pierwszy znak jest znakiem nowej linii, head
zostanie ustawiony na pusty ciąg znaków, co uniemożliwi rozróżnienie między pustym wejściem a wejściem zaczynającym się od pustej linii.head=$(head -c 1)
ponieważ jeśli pierwszy znak jest znakiem nowej linii, podstawienie polecenia usunie ostatnią linię, uniemożliwiając rozróżnienie między pustym wejściem a wejściem zaczynającym się od pustej linii.cat
przez </dev/stdin
do mikroskopijnej przyrostu wydajności.Jeśli nie masz nic przeciwko przechowywaniu w pamięci całych danych pośrednich, oto bardzo nieznacznie prostsza implementacja pipe_if_not_empty
.
pipe_if_not_empty () {
input=$(cat; echo a);
if [ "x$input" != x"a" ]; then
{ printf %s "${input%a}"; } | "$@"
fi
}
Oto nieco prostsza implementacja z następującymi zastrzeżeniami:
Ponownie całe dane są przechowywane w pamięci.
pipe_if_not_empty () {
input=$(cat);
if [ "x$input" != x"" ]; then
{ printf '%s\n' "${input}"; } | "$@"
fi
}
To powinno ci pomóc
$ --a function-- | [ xargs -r ] --another function--
Przykład
$ echo -e "\n\n" | xargs -r ls
$ # No output. ls did not run.
$ echo -e "\n\n1" | xargs -r ls
ls: cannot access 1: No such file or directory
To proste, ale powinno działać dla Ciebie. Jeśli twoja „funkcja” wysyła pusty ciąg lub nawet nowy wiersz w dół rurociągu, xargs -r uniemożliwi przejście do „innej funkcji”.
Dokumentacja xargs: http://www.oreillynet.com/linux/cmd/cmd.csp?path=x/xargs
-r, --no-run-if-empty
Do not run command if standard input contains only blanks.
Poniższa funkcja próbuje odczytać pierwszy bajt, a jeśli pomyślne echo tego bajtu, a pozostałe koty. Powinien być wydajny i w 100% przenośny.
if_read() {
IFS="" read -rN 1 BYTE && { echo -nE "$BYTE"; cat; } | "$@";
}
Przypadki testowe:
$ echo -n | if_read wc -c
$ echo | if_read wc -c
1
$ echo -en "\nX" | if_read wc -c
2
$
echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" foo@bar.com
. Uważa, że line
i here
oboje są adresatami wiadomości e-mail, a nie tokenami w temacie. Muszę uciec od "
otaczającego tematu, aby go uruchomić. Jednak pipe_if_not_empty
funkcja z zaakceptowanej odpowiedzi działa dla mnie nawet bez niczego.
Przynajmniej coś takiego działa:
yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi
Należy pamiętać, że powyższe rozważa wstawianie wierszy i inne znaki specjalne jako dane wyjściowe, więc pusty wiersz jest przekazywany do tego, jeśli instrukcja będzie uważana za wynik. Po prostu podnieś limit -gt, jeśli twój wynik powinien zwykle przekraczać 1 bajt :)
yourothercommand
nigdy nie widzi wyniku yourcommand
.
Zamiast sender | receiver
:
tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | receiver; fi; }
sender | tester
Możesz też uczynić to bardziej ogólnym celem, zmieniając go tak, aby akceptował program odbierający jako argument jak w odpowiedzi Gillesa:
tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | "$@"; fi; }
sender | tester receiver