Читайте построчно в скрипте bash - PullRequest
45 голосов
/ 10 января 2011

Я хочу сделать следующее, читать строку за строкой файла и использовать значение для каждой строки в качестве параметров

FILE="cat test"
echo "$FILE" | \
while read CMD; do
echo $CMD
done

но когда я делаю echo $ CMD, он просто возвращает cat: S

Ответы [ 7 ]

106 голосов
/ 10 января 2011
FILE=test

while read CMD; do
    echo "$CMD"
done < "$FILE"

Перенаправление с < "$FILE" имеет несколько преимуществ перед cat "$FILE" | while ....Это позволяет избежать бесполезного использования cat , сохраняя ненужный дочерний процесс.Это также позволяет избежать распространенной ошибки, когда цикл работает в подоболочке.В bash команды в конвейере | выполняются в подоболочках, что означает, что назначения переменных теряются после окончания цикла.Перенаправление с < не имеет такой проблемы, поэтому вы можете использовать $CMD после цикла или изменить другие переменные внутри цикла.Это также, опять же, позволяет избежать ненужных дочерних процессов.

Существуют некоторые дополнительные улучшения, которые можно сделать:

  • Добавьте IFS=, чтобы read не обрезал ведущие изавершающие пробелы в каждой строке.
  • Добавьте -r для чтения, чтобы предотвратить интерпретацию обратных слешей как escape-последовательностей.
  • Строчные буквы CMD и FILE.Соглашение bash касается только окружения, а переменные внутренней оболочки пишутся в верхнем регистре.
  • Используйте printf вместо echo, что более безопасно, если $cmd - строка типа -n, которую echo будет интерпретироватькак флаг.
file=test

while IFS= read -r cmd; do
    printf '%s\n' "$cmd"
done < "$file"
80 голосов
/ 10 января 2011

То, что у вас есть, - это передача текста "cat test" в цикл.

Вы просто хотите:

cat test | \
while read CMD; do
    echo $CMD
done
13 голосов
/ 14 сентября 2012

xargs - наиболее гибкое решение для разделения вывода на аргументы команды.

Он также очень удобочитаем и прост в использовании благодаря простой параметризации.

Формат xargs -n $NUMLINES mycommand.

Например, для echo каждой отдельной строки в файле /tmp/tmp.txt вы должны сделать:

cat /tmp/tmp.txt | xargs -n 1 echo

Или diff каждая последующая пара файлов, перечисленных в виде строк в файле с вышеуказанным именем, которое вы бы сделали:

cat /tmp/tmp.txt | xargs -n 2 diff

-n 2 инструктирует xargs потреблять и передавать в качестве отдельных аргументов две строки того, что вы передали ему за раз.

Вы можете настроить xargs для разделения на разделители, кроме возврата каретки / перевода строки.

Используйте man xargs и Google, чтобы узнать больше о мощи этой универсальной утилиты.

2 голосов
/ 10 января 2011

Если вы хотите использовать каждую из строк файла в качестве параметров командной строки для своего приложения, вы можете использовать команду xargs.

xargs -a <params_file> <command>

Файл параметров с:

a
b
c
d

и файл tr.py:

import sys
print sys.argv

Исполнение

xargs -a params ./tr.py

дает результат:

['./tr.py', 'a', 'b', 'c', 'd']
2 голосов
/ 10 января 2011

Вы хотите сделать:

cat test | \
while read CMD; do
echo $CMD
done
0 голосов
/ 01 декабря 2018
while read CMD; do
    echo $CMD
done  << EOF
data line 1
data line 2
..
EOF
0 голосов
/ 10 января 2011

Правильная версия вашего скрипта выглядит следующим образом;

FILE="cat test"
$FILE | \
while read CMD; do
echo $CMD
done

Однако такого рода косвенное обращение - ввод вашей команды в переменную с именем FILE - не требуется. Используйте одно из уже предоставленных решений. Я просто хотел указать на вашу ошибку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...