Чтение вывода команды в массив в 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