Чтение вывода команды в массив в Bash

Мне нужно прочитать вывод команды из моего скрипта в массив. Команда, например:

ps aux | grep | grep | x 

и это дает вывод построчно, как это:

10
20
30

Мне нужно прочитать значения из вывода команды в массив, а затем я сделаю некоторую работу, если размер массива меньше трех.

 smonff23 мар. 2016 г., 14:38
Пожалуйста, @ barp, пометьте вопрос как ответивший.
 codeforester25 июл. 2018 г., 22:06
Связанные с:Looping through the content of a file in Bash поскольку чтение вывода команды посредством подстановки процесса аналогично чтению из файла.
 James24 мар. 2014 г., 19:59
Привет @barp, ОТВЕТЬТЕ НА ВАШИ ВОПРОСЫ, чтобы ваш тип не истощал всю общину.
 DDPWNAGE04 окт. 2015 г., 08:31
@ James проблема не в том, что он не отвечает на свой вопрос ... это сайт Q / A. Он просто неmark им как ответили. Он должен отметить их. Подсказка. @ барп

Ответы на вопрос(3)

если выходные данные команды будут содержать пробелы (что довольно часто) или такие символы как*, ?, [...].

Чтобы получить выходные данные команды в массиве, существует по существу два способа:

With Bash≥4 use mapfile—it's the most efficient:

mapfile -t my_array < <( my_command )

Otherwise, a loop reading the output (slower, but safe):

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=

Но теперь давайте использовать другую команду:

$ echo "* one two"; echo "[three four]"
* one two
[three four]
$ IFS=

Это потому, что у меня есть файл с именемt в текущем каталоге & # x2026; и это имя файла соответствуетglob [three four]& # X2026; на данный момент некоторые люди рекомендуют использоватьset -f отключить globbing: но посмотрите на это: вы должны изменитьIFS и использоватьset -f чтобы иметь возможность исправить неисправную технику (и вы даже не исправляете ее)! делая это, мы действительноfighting against оболочка, а неworking with the shell.

$ mapfile -t my_array < <( echo "* one two"; echo "[three four]")
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="[three four]")'

здесь мы работаем с оболочкой!

\n' $ my_array=( $(echo "one two"; echo "three four") ) $ declare -p my_array declare -a my_array='([0]="one two" [1]="three 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 в текущем каталоге & # x2026; и это имя файла соответствуетglob [three four]& # X2026; на данный момент некоторые люди рекомендуют использоватьset -f отключить globbing: но посмотрите на это: вы должны изменитьIFS и использоватьset -f чтобы иметь возможность исправить неисправную технику (и вы даже не исправляете ее)! делая это, мы действительноfighting against оболочка, а неworking with the shell.

$ mapfile -t my_array < <( echo "* one two"; echo "[three four]")
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="[three four]")'

здесь мы работаем с оболочкой!

\n' $ my_array=( $(echo "* one two"; echo "[three four]") ) $ declare -p my_array declare -a my_array='([0]="* one two" [1]="t")' $ # What?

Это потому, что у меня есть файл с именемt в текущем каталоге & # x2026; и это имя файла соответствуетglob [three four]& # X2026; на данный момент некоторые люди рекомендуют использоватьset -f отключить globbing: но посмотрите на это: вы должны изменитьIFS и использоватьset -f чтобы иметь возможность исправить неисправную технику (и вы даже не исправляете ее)! делая это, мы действительноfighting against оболочка, а неworking with the shell.

$ mapfile -t my_array < <( echo "* one two"; echo "[three four]")
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="[three four]")'

здесь мы работаем с оболочкой!

\n' $ my_array=( $(echo "one two"; echo "three four") ) $ declare -p my_array declare -a my_array='([0]="one two" [1]="three 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 в текущем каталоге & # x2026; и это имя файла соответствуетglob [three four]& # X2026; на данный момент некоторые люди рекомендуют использоватьset -f отключить globbing: но посмотрите на это: вы должны изменитьIFS и использоватьset -f чтобы иметь возможность исправить неисправную технику (и вы даже не исправляете ее)! делая это, мы действительноfighting against оболочка, а неworking with the shell.

$ mapfile -t my_array < <( echo "* one two"; echo "[three four]")
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="[three four]")'

здесь мы работаем с оболочкой!

 16 янв. 2017 г., 16:46
Расширяя полезную заметку @ GenePavlovsky, сценарий также должен запускаться с помощью команды bash.bash my_script.sh а не команда shsh my_script.sh
 16 янв. 2017 г., 16:53
@Vito: действительно, этот ответ только для Bash, но это не должно быть проблемой, поскольку строго совместимые оболочки POSIX даже не реализуют массивы (sh а такжеdash вообще ничего не знаю о массивах, кроме, конечно, позиционных параметров[email protected] массив).
 19 апр. 2016 г., 22:37
Кстати, чтобы использовать этот синтаксис< <(command) в сценариях оболочки строка shebang должна быть#!/bin/bash - если запустить как#!/bin/sh, bash завершится с ошибкой синтаксиса.
 19 апр. 2016 г., 22:36
Это здорово, я никогда не слышал оmapfile раньше, это именно то, чего мне не хватало годами. Я думаю, последние версииbash У меня так много хороших новых функций, что мне просто нужно потратить несколько дней на чтение документации и написание хорошей таблицы.
 19 апр. 2016 г., 22:44
Еще одно примечание, если вы ожидаете, что ваш<( ... ) вложенная команда может завершиться с ошибкой, код ошибки не распространяется за пределы строки. Например.mapfile -t my_array < <(false) || echo 'failed' >&2 не эхомfailedместо для добавления проверки ошибок должно быть внутри:mapfile -t my_array < <(false || echo 'failed' >&2) выходыfailed, Хотелось бы, чтобы была возможность распространять код ошибки снаружи.set -e -o pipefail не помогает.

что вы собираетесь поместить файлы и имена каталогов (в текущей папке) в массив и сосчитать его элементы. Сценарий будет как;

my_array=( `ls` )
my_array_length=${#my_array[@]}
echo $my_array_length

Или вы можете перебрать этот массив, добавив следующий скрипт:

for element in "${my_array[@]}"
do
   echo "${element}"
done
 07 июн. 2018 г., 06:03
Страшная идея по причинам, указанным в ответе выше

Ты можешь использовать

my_array=( $(<command>) )

сохранить вывод команды<command> в массивmy_array.

Вы можете получить доступ к длине этого массива, используя

my_array_length=${#my_array[@]}

Теперь длина сохраняется вmy_array_length.

 10 янв. 2019 г., 18:05
Не работает, если строки из & lt; command & gt; содержать пробелы.
 30 июн. 2016 г., 02:44
Что если выходные данные $ (команда) имеют пробелы и несколько строк с пробелами? Я добавил & quot; $ (команда) & quot; и он помещает все выходные данные из всех строк в первый элемент [0] массива.
 16 янв. 2017 г., 17:59
@ ikwyl6 Обходной путь - это присвоить вывод команды переменной, а затем создать из нее массив или добавить его в массив.VAR="$(<command>)" а потомmy_array=("$VAR") или жеmy_array+=("$VAR")

Ваш ответ на вопрос