Обработка входа линию за линией (с пустыми строками) от оболочки

В документах, в которых говорится, что они допустимы для Samba 3 и 4, говорится:

"... удостоверьтесь, что Ваш smbd компилируется с поддержкой CUPS":

# smbd -b | grep CUPS
   HAVE_CUPS_CUPS_H
   HAVE_CUPS_LANGUAGE_H
   HAVE_CUPS
   HAVE_LIBCUPS

3
13.02.2015, 17:05
3 ответа

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

    i=1
    while read -r line; do
        eval VAL$i=\$line
        i=$((i+1))
    done <<EOF
$(my_command)
EOF

Работает отлично.

Обновление: учтены отзывы Жиля и mikeserv.

0
27.01.2020, 21:19

Сделайте это таким образом:

i=1
my_command | while read line; do
    echo $line
    eval VAL$i="$line"
    i=$((i+1))
done

, поскольку вывод команды является линейкой чтения по строке, эти строки обрабатываются индивидуально (включая пустые Линии) без необходимости сначала хранить эти строки в переменной. Это также сохраняет память, так как вывод не заканчивается в памяти дважды, и сценарий Bash может начать обработку этих строк, как только они выводят, а не только после завершения команды.

Отредактируйте: поскольку переменные VALX устанавливаются в вышеупомянутой поверхности, необходима модификация:

eval `i=1
my_command | while read line; do
    # echo $line
    echo "VAL$i=\"$line\""
    i=$((i+1))
done`

, если вам действительно нужны Echo $ Line , некоторые модификации будут необходимы.

1
27.01.2020, 21:19

Работоспособный цикл оболочки может выглядеть так ...

set -f -- "-$-"' -- "$@" '"
    ${IFS+IFS=\$2} ${out+out=\$3}" \
    "$IFS" "$out" "$@"
IFS='
';for out in $(my command|grep -n '.\|')
do  : something with "${out%%:*}" and "${out#*:}"
done
unset IFS out
eval "set +f $1"
shift 3

Вам нужно только расположить его так, чтобы не было пустых строк. Хотя я изначально предложил для этой цели nl , при второй мысли есть небольшая вероятность того, что логический разделитель страниц nl может появиться на входе и исказить его вывод (это будет на самом деле приводит к появлению пустой строки и может повлиять на то, какая строка была пронумерована - хотя это очень удобная функция для других целей) . За исключением без интерпретации логических разрывов страниц, результаты grep -n '. \ |' будут идентичными.

Используя подобный конвейер с небольшой заменой параметров, вы можете не только избежать проблемы с пустой строкой, но также, что каждая итерация имеет предварительно пронумерованный одновременно - (номер текущей итерации теперь будет равным Глава каждого значения обслуживает вас за $ out , за которым следует : ) .

Строки set ... IFS = ... предназначены для того, чтобы гарантировать, что состояние оболочки будет восстановлено до того места, в котором вы его оставили до изменения. Эти меры предосторожности могут оказаться излишними, если это сценарий, а не функция. Тем не менее, вы должны по крайней мере установить -f перед разделением оболочки, чтобы избежать непреднамеренного подстановки на ваш ввод.


Но о (d) ash и <( подстановка процесса )

Затем снова в Debian ( тире ) производный ash (например, busybox ash ) , вы можете обнаружить, что его обработка ссылок файловых дескрипторов и здесь-документов обеспечивает лучшую альтернативу тому, что вы могли бы привыкать делать с <( подстановка процесса ) .

Рассмотрим этот пример:

exec "$((i=3))"<<R "$((o=4))"<<W 3<>/dev/fd/3 4<>/dev/fd/4
R
W

sed -u 's/.*/here I am./' <&"$o" >&"$i" &
echo "hey...sed?" >&"$o"
head -n1          <&"$i"

Потому что тире и производные здесь - документы с анонимными каналами, а не (как большинство других оболочек) с обычными файлами, и потому что / dev / fd / [num] ссылки в системах Linux обеспечивают косвенный способ ссылки на файл резервной копии файлового дескриптора (даже если на него нельзя ссылаться в файловой системе - например, для анонимных pipe) Вышеупомянутая последовательность демонстрирует очень простые средства настройки того, что некоторые оболочки могут называть сопроцессом . Например, в busybox ash или dash в системе Linux (я не ручаюсь за другие) выше будет напечатано:

here I am.

... и будет продолжать делать это до тех пор, пока оболочка не закроет свои файловые дескрипторы $ i и $ o . Он использует переключатель -u nbuffered, который предлагает GNU sed , чтобы избежать проблем с буферизацией, но даже без него входные данные фонового процесса могут быть отфильтрованы и conv = sync хронизируется по блокам \ 0NUL байтов с dd в конвейере, если это необходимо.

Вот способ, которым я обычно использую вышеуказанное с sed в интерактивной оболочке:

: & SEDD=$$$!
sed -un "/^$SEDD$/!H;//!d;s///;x;/\n/!q;s///;s/%/&&/g;l" <&"$o" >&"$i" &

...который является фоном для sed , который будет читать и сохранять ввод до тех пор, пока не встретит уникальный разделитель, после чего он удвоит любое вхождение % в своем старом буфере H и напечатайте в моем exec 'd анонимном конвейере строку, удобную для формата printf с экранированием на языке C, в одной строке - или, в нескольких строках, если результат превышает 80 символов. Последний - для GNU sed - может быть обработан с помощью sed -l0 , который является переключателем, который инструктирует sed никогда не переносить строки на \ , или еще как:

fmt=
while IFS= read -r r <&"$i" 
      case $r in (*$) 
      ! fmt=$fmt$r ;;esac
do    fmt=$fmt${r%?} 
done

В любом случае, я создаю его буфер как:

echo something at sed >&"$o"
printf '%s\n' more '\lines%' at sed "$SEDD" >&"$o"

Затем я втягиваю его, как ...

IFS= read -r fmt <&"$i"

Вот как выглядит содержимое $ fmt после:

printf %s\\n "$fmt"
something at sed\nmore\n\\lines%%\nat\nsed$

sed также будет выполнять восьмеричные escape-символы в стиле C для непечатаемых символов.

Так что я могу использовать его как ...

printf "%d\n${fmt%$}\n" 1 2 3

... который печатает ...

1
something at sed
more
\lines%
at
sed
2
something at sed
more
\lines%
at
sed
3
something at sed
more
\lines%
at
sed

И я могу убить sed и освободить каналы по мере необходимости, например ...

printf %s\\n "$SEDD" "$SEDD" >&"$o"
exec "$i">&- "$o">&-

Это то, что вы можете сделать, когда вам нужно удерживать fd, а не использовать его только один раз. Вы можете поддерживать обратную трубу столько, сколько вам нужно -и он более безопасен, чем именованный канал, потому что ядро ​​не предлагает эти ссылки никому, кроме процесса, которому они принадлежат (ваша оболочка) , тогда как именованный канал может быть найден (и прослушано / украдено) в файловой системе любым процессом с разрешениями на его ссылочный файл.

Чтобы делать подобные вещи в оболочке, которая выполняет подстановку, вы, вероятно, можете сделать что-то вроде ...

eval "exec [num]<>"<(:)

... но я никогда не пробовал.

3
27.01.2020, 21:19

Теги

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