Чтение вывода команды в массив в Bash
Мне нужно прочитать вывод команды в моем script в массив. Например, команда:
ps aux | grep | grep | x
и он выводит строку строки следующим образом:
10
20
30
Мне нужно прочитать значения из вывода команды в массив, а затем я сделаю некоторую работу, если размер массива < 3.
Ответы
Ответ 1
Вы можете использовать
my_array=( $(<command>) )
чтобы сохранить вывод команды <command>
в массив my_array
.
Вы можете получить доступ к длине этого массива с помощью
my_array_length=${#my_array[@]}
Теперь длина сохраняется в my_array_length
.
Ответ 2
Другие ответы будут разбиты, если вывод команды содержит пробелы (которые довольно часты) или символы glob, такие как *
, ?
, [...]
.
Чтобы получить вывод команды в массиве, существует по существу два способа:
-
С Bash ≥4 используйте mapfile
-it наиболее эффективно:
mapfile -t my_array < <( my_command )
-
В противном случае цикл, считывающий вывод (медленнее, но безопасно):
my_array=()
while IFS= read -r line; do
my_array+=( "$line" )
done < <( my_command )
Вероятно, вы увидите много этого:
my_array=( $( my_command) )
Но не используйте его! Посмотрите, как это сломалось:
$ # this is the command used to test:
$ echo "one two"; echo "three four"
one two
three four
$ my_array=( $( echo "one two"; echo "three four" ) )
$ declare -p my_array
declare -a my_array='([0]="one" [1]="two" [2]="three" [3]="four")'
$ # Not good! now look:
$ mapfile -t my_array < <(echo "one two"; echo "three four")
$ declare -p my_array
declare -a my_array='([0]="one two" [1]="three four")'
$ # Good!
Затем некоторые люди рекомендуют использовать IFS=$'\n'
, чтобы исправить это:
$ IFS=$'\n'
$ my_array=( $(echo "one two"; echo "three four") )
$ declare -p my_array
declare -a my_array='([0]="one" [1]="two" [2]="three" [3]="four")'
$ # It works!
Но теперь можно использовать другую команду:
$ echo "* one two"; echo "[three four]"
* one two
[three four]
$ IFS=$'\n'
$ my_array=( $(echo "* one two"; echo "[three four]") )
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="t")'
$ # What?
Это потому, что у меня есть файл с именем t
в текущем каталоге... и это имя файла сопоставляется с glob [three four]
... в этот момент некоторые люди рекомендуют использовать set -f
для отключения globbing: но посмотрите на него: вам нужно изменить IFS
и использовать set -f
, чтобы исправить сломанную технику (и вы даже не исправляете ее)! при этом мы действительно боремся с оболочкой, не работая с оболочкой.
$ mapfile -t my_array < <( echo "* one two"; echo "[three four]")
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="[three four]")'
здесь мы работаем с оболочкой!
Ответ 3
Представьте, что вы собираетесь поместить файлы и имена каталогов (под текущей папкой) в массив и подсчитать его элементы. script будет выглядеть следующим образом:
my_array=( `ls` )
my_array_length=${#my_array[@]}
echo $my_array_length
Или вы можете перебрать этот массив, добавив следующий script:
for element in "${my_array[@]}"
do
echo "${element}"
done