Bash: конвейер 'find' output в ' readarray '

socat может делать это через многоадресную рассылку по локальной сети.

host1:$ socat STDIO UDP4-DATAGRAM:224.1.0.1:6666,bind=:6666,range=192.168.1.0/24,ip-add-membership=224.1.0.1:192.168.1.11
host2:$ socat STDIO UDP4-DATAGRAM:224.1.0.1:6666,bind=:6666,range=192.168.1.0/24,ip-add-membership=224.1.0.1:192.168.1.12
host3:$ socat STDIO UDP4-DATAGRAM:224.1.0.1:6666,bind=:6666,range=192.168.1.0/24,ip-add-membership=224.1.0.1:192.168.1.13

Вот числа:

  • 224.1.0.1 - IP-адрес многоадресной рассылки. Здесь будет работать любой многоадресный IP. Должен быть одинаковым для всех клиентов.
  • 6666 - Номер порта. Любой неиспользованный номер> 1024 подойдет. То же самое для всех клиентов.
  • 192.168.1.0/24 - Допустимый диапазон клиентской сети.
  • 192.168.1.11 - IP-адрес вашего хоста.

Дополнительная информация об использовании socat для многоадресной рассылки на http://www.dest-unreach.org/socat/doc/socat-multicast.html

9
17.02.2016, 18:16
4 ответа

При использовании конвейера bash запускает команды в подоболочках.Следовательно, массив заполняется, но в подоболочке, поэтому родительская оболочка не имеет к нему доступа.

Использовать замену процесса:

readarray FILES < <(find)

Обратите внимание, что это не работает для файлов с символами новой строки в их именах. Если это может быть так, вам понадобится более сложный синтаксис:

readarray -d '' < <(find -print0)
15
27.01.2020, 20:04

Правильное решение:

unset a; declare -a a
while IFS= read -r -u3 -d $'\0' file; do
    a+=( "$file" )        # or however you want to process each file
done 3< <(find /tmp -type f -print0)

Это похоже на то, что Greg's BashFAQ 020 подробно объясняет, а этот ответ охватывает .

Нет проблем с файлами с нечетными именами (которые не содержат NUL в имени), с пробелами или новыми строками. Результат записывается в массив, что делает его полезным для дальнейшей обработки.

8
27.01.2020, 20:04

readarray также может читать из stdin

readarray FILES <<< "$(find . -name "file*")"; echo "${#FILES[@]}"
3
27.01.2020, 20:04

С shopt -s lastpipeрешение, показанное в исходном вопросе, работает, так как тогда часть после последнего |выполняется в том же процессе, что и большая часть скрипта:

shopt -s lastpipe

# This is just the code form the original question.
# Of course it could be done with -print0, etc.
declare -a FILES
find. -name "name*" | readarray -t FILES
echo find and readarray exit status: "${PIPESTATUS[@]}"
echo "${FILES[@]}"
echo "${#FILES[@]}"

Однако это практично только в том случае, если lastpipeможно сделать проектным -широким стандартом (, возможно, у вас уже есть такие общие настройки для set -uи т. д. ). Также знайте, что lastpipeработает только для не -интерактивных оболочек.

Другая типичная замена конвейера,< <(...)(замена процесса ), имеет проблему, состоящую в том, что довольно сложно проверить, успешно ли завершился дочерний процесс.

1
26.05.2021, 10:58

Теги

Похожие вопросы