Muszę odczytać dane wyjściowe polecenia w moim skrypcie do tablicy. Polecenie to na przykład:
ps aux | grep | grep | x
i daje wynik wiersz po wierszu w następujący sposób:
10
20
30
Muszę odczytać wartości z danych wyjściowych polecenia do tablicy, a następnie wykonam trochę pracy, jeśli rozmiar tablicy jest mniejszy niż trzy.
Odpowiedzi:
Pozostałe odpowiedzi pęknie jeśli wyjście komendy zawiera spacje (co jest dość częste) lub znaki jak glob
*
,?
,[...]
.Aby uzyskać wynik polecenia w tablicy, z jednym wierszem na element, istnieją zasadniczo 3 sposoby:
Z Bash≥4 użyj
mapfile
- jest najbardziej wydajny:W przeciwnym razie pętla odczytująca wyjście (wolniej, ale bezpiecznie):
Jak zasugerował Charles Duffy w komentarzach (dzięki!), Poniższe mogą działać lepiej niż metoda pętli w numerze 2:
Upewnij się, że używasz dokładnie tego formularza, tj. Upewnij się, że masz następujące:
IFS=$'\n'
w tym samym wierszu coread
instrukcja: spowoduje to ustawienie zmiennej środowiskowej tylkoIFS
dlaread
instrukcji. Więc w ogóle nie wpłynie to na resztę twojego skryptu. Celem tej zmiennej jest nakazanieread
przerwania strumienia przy znaku EOL\n
.-r
: To jest ważne. Mówi,read
aby nie interpretować odwrotnych ukośników jako sekwencji ucieczki.-d ''
: zwróć uwagę na spację między-d
opcją a jej argumentem''
. Jeśli nie zostawisz tutaj spacji,''
nigdy nie będzie widoczne, ponieważ zniknie w kroku usuwania cytatu, gdy Bash przeanalizuje instrukcję. To mówi,read
aby przestać czytać na bajcie zerowym. Niektórzy piszą to jako-d $'\0'
, ale tak naprawdę nie jest to konieczne.-d ''
jest lepiej.-a my_array
mówi,read
aby wypełnić tablicęmy_array
podczas czytania strumienia.printf '\0'
instrukcji późniejmy_command
, aby toread
powróciło0
; to właściwie nie jest wielka sprawa, jeśli tego nie zrobisz (otrzymasz po prostu kod powrotu1
, co jest w porządku, jeśli nie używaszset -e
- czego i tak nie powinieneś), ale po prostu miej to na uwadze. Jest czystszy i bardziej poprawny semantycznie. Zauważ, że różni się to odprintf ''
, które nic nie wyświetla.printf '\0'
wypisuje bajt zerowy, potrzebny,read
aby szczęśliwie przestał tam czytać (pamiętasz-d ''
opcję?).Jeśli możesz, tj. Jeśli masz pewność, że Twój kod będzie działał na Bash≥4, użyj pierwszej metody. Widać też, że jest krótszy.
Jeśli chcesz użyć
read
, pętla (metoda 2) może mieć przewagę nad metodą 3, jeśli chcesz wykonać pewne przetwarzanie podczas odczytywania wierszy: masz do niej bezpośredni dostęp (poprzez$line
zmienną z podanego przykładu) i masz również dostęp do już przeczytanych wierszy (poprzez tablicę${my_array[@]}
z przykładu, który podałem).Zauważ, że
mapfile
umożliwia to wywołanie zwrotne w każdej przeczytanej linii, aw rzeczywistości możesz nawet powiedzieć mu, aby wywoływał to wywołanie zwrotne tylko po przeczytaniu N linii; spójrz nahelp mapfile
i opcje-C
i-c
tam. (Moja opinia na ten temat jest taka, że jest to trochę niezgrabne, ale czasami może być używane, jeśli masz tylko proste rzeczy do zrobienia - nie bardzo rozumiem, dlaczego zostało to wdrożone!).Teraz powiem ci, dlaczego następująca metoda:
jest uszkodzony, gdy są spacje:
Wtedy niektórzy ludzie zalecą użycie,
IFS=$'\n'
aby to naprawić:Ale teraz użyjmy innego polecenia, z globami :
Dzieje się tak, ponieważ mam plik o nazwie
t
w bieżącym katalogu… a ta nazwa pliku jest dopasowana przez glob[three four]
… w tym momencie niektórzy ludzie zalecaliby użycieset -f
do wyłączenia globbingu: ale spójrz na to: musisz zmienićIFS
i użyć,set -f
aby móc naprawić zepsuta technika (a nawet tego nie naprawiasz)! robiąc to, naprawdę walczymy z powłoką, a nie z nią .tutaj pracujemy z powłoką!
źródło
mapfile
, właśnie tego brakowało mi od lat. Wydaje mi się, że ostatnie wersjebash
mają tak wiele fajnych nowych funkcji, że powinienem poświęcić kilka dni na przeczytanie dokumentacji i spisanie fajnej ściągawki.< <(command)
w skryptach powłoki, wiersz shebang powinien wyglądać tak#!/bin/bash
- jeśli zostanie uruchomiony jako#!/bin/sh
, bash zakończy działanie z błędem składni.bash my_script.sh
a nie z poleceniem shsh my_script.sh
sh
idash
nie wiedzą w ogóle o tablicach, z wyjątkiem, oczywiście,$@
tablica parametrów pozycyjnych ).IFS=$'\n' read -r -d '' -a my_array < <(my_command && printf '\0')
- zarówno działa poprawnie w bash 3.x, jak i przechodzi przez nieudany kod wyjścia zmy_command
doread
.Możesz użyć
do przechowywania danych wyjściowych polecenia
<command>
w tablicymy_array
.Możesz uzyskać dostęp do długości tej tablicy za pomocą
Teraz długość jest przechowywana w
my_array_length
.źródło
VAR="$(<command>)"
a potemmy_array=("$VAR")
lubmy_array+=("$VAR")
Wyobraź sobie, że zamierzasz umieścić pliki i nazwy katalogów (w bieżącym folderze) w tablicy i policzyć jej elementy. Scenariusz byłby taki;
Lub możesz iterować po tej tablicy, dodając następujący skrypt:
Zwróć uwagę, że jest to podstawowa koncepcja i uważa się, że dane wejściowe zostały wcześniej oczyszczone, tj. Usunięcie dodatkowych znaków, obsługa pustych ciągów itd. (Co jest poza tematem tego wątku).
źródło