Мне нужно прочитать вывод команды в моем скрипте в массив. Например, команда:
ps aux | grep | grep | x
и выводит строку за строкой вот так:
10
20
30
Мне нужно прочитать значения из вывода команды в массив, а затем я выполню некоторую работу, если размер массива меньше трех.
Ответы:
Другие ответы сломается , если вывод команды содержит пробелы (которые довольно часто) или шарик символы , такие как
*
,?
,[...]
.Чтобы получить вывод команды в массиве с одной строкой на элемент, есть три способа:
При использовании Bash≥4
mapfile
- это наиболее эффективно:В противном случае цикл чтения вывода (более медленный, но безопасный):
Как предложил Чарльз Даффи в комментариях (спасибо!), Следующий метод может работать лучше, чем метод цикла в номере 2:
Убедитесь, что вы используете именно эту форму, т.е. убедитесь, что у вас есть следующее:
IFS=$'\n'
в той же строке, что иread
оператор: это установит только переменную средыIFS
дляread
оператора. Так что это никак не повлияет на остальную часть вашего скрипта. Назначение этой переменной - сообщитьread
о прерывании потока по символу EOL\n
.-r
: это важно. Он говоритread
не интерпретировать обратную косую черту как escape-последовательности.-d ''
: обратите внимание на пробел между-d
параметром и его аргументом''
. Если вы не оставите здесь пробел,''
он никогда не будет виден, поскольку он исчезнет на этапе удаления цитаты, когда Bash проанализирует оператор. Это говоритread
о прекращении чтения на нулевом байте. Некоторые люди пишут это как-d $'\0'
, но на самом деле это не обязательно.-d ''
лучше.-a my_array
сообщаетread
заполнить массивmy_array
при чтении потока.printf '\0'
оператор послеmy_command
, чтобыread
вернуть0
; на самом деле это не имеет большого значения, если вы этого не сделаете (вы просто получите код возврата1
, что нормально, если вы не используетеset -e
- что вам все равно не следует), но просто имейте это в виду. Он чище и семантически корректнее. Обратите внимание, что это отличается отprintf ''
, который ничего не выводит.printf '\0'
печатает нулевой байт, необходимыйread
для благополучного прекращения чтения (помните-d ''
опцию?).Если вы можете, т.е. если вы уверены, что ваш код будет работать на Bash≥4, используйте первый метод. Вы также можете видеть, что он короче.
Если вы хотите использовать
read
, цикл (метод 2) может иметь преимущество перед методом 3, если вы хотите выполнять некоторую обработку по мере чтения строк: у вас есть прямой доступ к нему (через$line
переменную в приведенном мной примере) и у вас также есть доступ к уже прочитанным строкам (через массив${my_array[@]}
в приведенном мной примере).Обратите внимание, что это
mapfile
дает возможность иметь функцию eval'd обратного вызова при чтении каждой строки, и фактически вы даже можете указать ему вызывать этот обратный вызов только каждые N прочитанных строк; посмотритеhelp mapfile
и варианты-C
и-c
там. (Я считаю, что это немного неуклюже, но иногда его можно использовать, если у вас есть только простые дела - я вообще не понимаю, почему это вообще было реализовано!).Теперь я расскажу, почему такой метод:
не работает, когда есть пробелы:
Тогда некоторые люди порекомендуют
IFS=$'\n'
исправить это с помощью:Но теперь давайте воспользуемся другой командой с глобусами :
Это потому, что у меня есть файл, который называется
t
в текущем каталоге ... и это имя файла совпадает с глобусом[three four]
... на этом этапе некоторые люди рекомендуют использоватьset -f
для отключения глобализации: но посмотрите на это: вы должны изменитьIFS
и использовать,set -f
чтобы иметь возможность исправить сломанная техника (а вы ее даже не исправляете)! при этом мы действительно сражаемся с оболочкой, а не с оболочкой .здесь мы работаем с оболочкой!
источник
mapfile
чем я раньше не слышал , это именно то, чего мне не хватало годами. Я думаю, что в последних версияхbash
есть так много хороших новых функций, что мне просто нужно потратить несколько дней на чтение документации и составление хорошей шпаргалки.< <(command)
в сценариях оболочки, строка shebang должна быть#!/bin/bash
- если запускать от имени#!/bin/sh
, bash выйдет с синтаксической ошибкой.bash my_script.sh
а не команды shsh my_script.sh
sh
иdash
вообще не знают о массивах, кроме, конечно, для$@
массив позиционных параметров ).IFS=$'\n' read -r -d '' -a my_array < <(my_command && printf '\0')
- она работает правильно в bash 3.x, а также проходит через статус неудачного выхода изmy_command
вread
.Ты можешь использовать
для сохранения вывода команды
<command>
в массивmy_array
.Вы можете получить доступ к длине этого массива, используя
Теперь длина сохраняется в
my_array_length
.источник
VAR="$(<command>)"
а потомmy_array=("$VAR")
илиmy_array+=("$VAR")
Представьте, что вы собираетесь поместить имена файлов и каталогов (в текущей папке) в массив и подсчитать его элементы. Сценарий был бы похож;
Или вы можете перебрать этот массив, добавив следующий скрипт:
Обратите внимание, что это основная концепция, и ввод считается очищенным раньше, т.е. удалением лишних символов, обработкой пустых строк и т. Д. (Что не входит в тему этой темы).
источник