Poniższa ifnotemptyfunkcja 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 --foopod sink --barpisząc source --foo | pipe_if_not_empty sink --bar.
Spodziewałbym się, że ta implementacja będzie działać na wszystkich platformach POSIX / Unix, choć ściśle mówiąc, nie jest zgodna ze standardami: polega na tym, że ddnie czyta więcej niż jeden bajt, który czytał na swoim standardowym wejściu.
Myślę, że head -c 1byłby odpowiednim zamiennikiem dla dd bs=1 count=1 2>/dev/nullsystemu Linux.
Z drugiej strony head -n 1nie byłby odpowiedni, ponieważ headzwykle 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 heada nawet read -r -n 1 headnie są tu odpowiednie, ponieważ jeśli pierwszy znak jest znakiem nowej linii, headzostanie 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.
Nie możemy po prostu pisać, 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.
W bash, ksh lub zsh, można zastąpić catprzez </dev/stdindo 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.
Oto nieco prostsza implementacja z następującymi zastrzeżeniami:
Dane wytworzone przez źródło są uważane za puste wtedy i tylko wtedy, gdy składają się wyłącznie ze znaków nowej linii. (To może być w rzeczywistości pożądane.)
Dane wprowadzane do ujścia kończą się dokładnie jednym znakiem nowego wiersza, bez względu na to, ile nowych wierszy kończy dane generowane przez źródło. (To może być problem.)
$ 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”.
ifne (1) z moreutils robi dokładnie to. Moreutils jest dostępny jako pakiet przynajmniej w Debianie i Ubuntu, prawdopodobnie także w innych dystrybucjach.
Ta funkcja nie działa dla mnie po uruchomieniu echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" [email protected]. Uważa, że linei hereoboje są adresatami wiadomości e-mail, a nie tokenami w temacie. Muszę uciec od "otaczającego tematu, aby go uruchomić. Jednak pipe_if_not_emptyfunkcja z zaakceptowanej odpowiedzi działa dla mnie nawet bez niczego.
kuzzooroo,
2
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 :)
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 rurysource --foo
podsink --bar
piszącsource --foo | pipe_if_not_empty sink --bar
.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 dladd 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 nawetread -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
.Oto nieco prostsza implementacja z następującymi zastrzeżeniami:
Ponownie całe dane są przechowywane w pamięci.
źródło
To powinno ci pomóc
Przykład
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ódło
ifne (1) z moreutils robi dokładnie to. Moreutils jest dostępny jako pakiet przynajmniej w Debianie i Ubuntu, prawdopodobnie także w innych dystrybucjach.
źródło
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.
Przypadki testowe:
źródło
echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" [email protected]
. Uważa, żeline
ihere
oboje są adresatami wiadomości e-mail, a nie tokenami w temacie. Muszę uciec od"
otaczającego tematu, aby go uruchomić. Jednakpipe_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 :)
źródło
yourothercommand
nigdy nie widzi wynikuyourcommand
.Zamiast
sender | receiver
:Możesz też uczynić to bardziej ogólnym celem, zmieniając go tak, aby akceptował program odbierający jako argument jak w odpowiedzi Gillesa:
źródło