Iteruj po danych wyjściowych polecenia w bash bez podpowłoki

9

Chcę zapętlić wynik polecenia bez tworzenia podpowłoki lub korzystania z pliku tymczasowego.

Początkowa wersja mojego skryptu wyglądała tak, ale to nie działa, ponieważ tworzy podpowłokę, a exitpolecenie kończy podpowłokę zamiast wymaganego skryptu głównego. Jest to część znacznie większego skryptu służącego do konfigurowania routingu zasad i wstrzymuje wykonanie, jeśli wykryje warunek, który spowoduje, że routing się nie powiedzie.

sysctl -a 2>/dev/null | grep '\.rp_filter' | while read -r -a RPSTAT ; do

  if [[ "0" != "${RPSTAT[2]}" ]] ; then
    echo >&2 "RP Filter must be disabled on all interfaces!"
    echo >&2 "The RP filter feature is incompatible with policy routing"
    exit 1
  fi
done

Jedną z sugerowanych alternatyw jest użycie takiego polecenia, aby uniknąć podpowłoki.

while read BLAH ; do echo $BLAH; done </root/regularfile

Wydaje mi się więc, że powinienem także móc użyć takiego polecenia, aby uniknąć podpowłoki i nadal otrzymywać dane wyjściowe z programu, który chcę.

while read BLAH ; do echo $BLAH; done <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Niestety użycie tego polecenia powoduje ten błąd.

-bash: syntax error near unexpected token `<(sysct ...

Jestem naprawdę zdezorientowany, ponieważ to działa.

cat <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Mogłem zapisać dane wyjściowe tego polecenia w pliku tymczasowym i użyć przekierowania w pliku tymczasowym, ale chciałem tego uniknąć.

Dlaczego więc przekierowanie powoduje błąd i czy mam inne opcje niż utworzenie pliku tymczasowego?

Zoredache
źródło

Odpowiedzi:

13

Przegapiłeś a <. Powinien być:

while read BLAH ; do echo $BLAH; done < <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Pomyśl o <(sysctl -a 2>/dev/null | grep '\.rp_filter')byciu plikiem.

dogbane
źródło
Wielkie dzięki. Czy dla mojej redakcji mogę skierować mnie na stronę podręcznika, pomocy lub stronę internetową, która to dokumentuje? Nie mogłem zmusić Google do wskazania mi czegoś przydatnego podczas próby wyszukiwania tego.
Zoredache
2
Google „proces zastępowania”. np tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB
dogbane
Należy zauważyć, że podstawienie <() używa deskryptorów plików i w niektórych systemach operacyjnych będzie przezroczyście tworzyć i używać plików tymczasowych.
ewindisch
@Zoredache: Po prostu wyszukaj <(w podręczniku bash (znajduje się pod „substytucją procesu”).
Gilles „SO- przestań być zły”
@ewindisch, jeśli narzędzie w przejrzysty sposób tworzy plik tymczasowy, który jest w porządku, po prostu nie chciałem go ręcznie tworzyć, gdy byłem całkiem pewien, że nie muszę.
Zoredache
0

Jeszcze kilka alternatyw, jeśli ktoś tu jeszcze przyjdzie ...

W zależności od powłoki można prawdopodobnie użyć set -o errexitwyjścia powłoki nadrzędnej, gdy polecenie (w tym podpowłoka) kończy się na niezerową, bez uwięzienia w ifbloku lub końcowym, &&lub ||, jak w

/bin/false || echo "ignoring error"

Lub, możesz mieć sygnał podpowłoki nadrzędny za pomocą kill i zmienną środowiskową $ PPID, jeśli jest dostępna.

Lub możesz przenieść blok while do funkcji i zwrócić 0/1 (jawnie zwrócić 0 po bloku while) i po prostu zrobić swój potok jak sysctl | grep | function || exit. Przypuszczam, że możesz również wstawić zwroty do bloku wbudowanego, ale funkcje są twoim przyjacielem. ;)

dannysauer
źródło