Как читать из файла или stdin в Bash?

В Perl следующий код будет считываться из файла, указанного в командной строке args или из stdin:

while () { print($_); } 

Это очень удобно. Я просто хочу знать, что является самым простым способом чтения из файла или stdin в bash.

Следующее решение читается из файла, если сценарий вызывается с именем файла в качестве первого параметра $1 отличие от стандартного ввода.

 while read line do echo "$line" done < "${1:-/dev/stdin}" 

Подстановка ${1:-...} принимает $1 если в противном случае используется имя файла стандартного ввода собственного процесса.

Возможно, самым простым решением является redirect stdin с помощью слияния оператора перенаправления:

 #!/bin/bash less <&0 

Stdin - дескриптор файла. Вышеуказанное отправляет входной stream в ваш скрипт bash в stdin less.

Подробнее о перенаправлении дескриптора файла .

Вот простейший способ:

 #!/bin/sh cat - 

Применение:

 $ echo test | sh my_script.sh test 

Чтобы назначить stdin для переменной, вы можете использовать: STDIN=$(cat -) или просто просто STDIN=$(cat) поскольку оператор не нужен (согласно комментарию @ mklement0 ).


Чтобы проанализировать каждую строку со стандартного ввода , попробуйте выполнить следующий скрипт:

 #!/bin/bash while IFS= read -r line; do printf '%s\n' "$line" done 

Чтобы прочитать из файла или stdin (если аргумент отсутствует), вы можете расширить его до:

 #!/bin/bash file=${1--} # POSIX-compliant; ${1:--} can be used either. while IFS= read -r line; do printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line" done < <(cat -- "$file") 

Заметки:

- read -r - Не обрабатывать символ обратной косой черты каким-либо особым образом. Рассмотрим каждую обратную косую черту как часть входной строки.

- Без установки IFS по умолчанию последовательности Space и Tab в начале и в конце строк игнорируются (обрезаются).

- Используйте printf вместо echo чтобы избежать печати пустых строк, когда строка состоит из одного -e , -n или -E . Однако существует обходное решение, используя env POSIXLY_CORRECT=1 echo "$line" который выполняет ваше внешнее echo GNU, которое его поддерживает. См .: Как эхо «-e»?

См .: Как читать stdin, когда аргументы не передаются? в stackoverflow SE

Решение echo добавляет новые строки, когда IFS разрывает входной stream. Ответ @ fgm может быть немного изменен:

 cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}" 

Я думаю, что это прямолинейный путь:

 $ cat reader.sh #!/bin/bash while read line; do echo "reading: ${line}" done < /dev/stdin 

-

 $ cat writer.sh #!/bin/bash for i in {0..5}; do echo "line ${i}" done 

-

 $ ./writer.sh | ./reader.sh reading: line 0 reading: line 1 reading: line 2 reading: line 3 reading: line 4 reading: line 5 

Цикл Perl в вопросе читается из всех аргументов имени файла в командной строке или из стандартного ввода, если файлы не указаны. Ответы, которые я вижу, кажутся обработкой одного файла или стандартного ввода, если файл не указан.

Хотя часто высмеивается как UUOC (бесполезное использование cat ), бывают случаи, когда cat является лучшим инструментом для работы, и можно утверждать, что это один из них:

 cat "[email protected]" | while read -r line do echo "$line" done 

Единственным недостатком этого является то, что он создает конвейер, работающий в под-оболочке, поэтому такие вещи, как присвоения переменных в цикле while, недоступны вне конвейера. Метод bash вокруг этого процесса заключается в замене процесса :

 while read -r line do echo "$line" done < <(cat "[email protected]") 

Это оставляет цикл while в основной оболочке, поэтому переменные, установленные в цикле, доступны вне цикла.

Поведение Perl с кодом, приведенным в OP, может принимать не один или несколько аргументов, и если аргумент представляет собой один дефис, это понимается как stdin. Кроме того, всегда возможно иметь имя файла с $ARGV . Ни один из ответов, представленных до сих пор, действительно имитирует поведение Perl в этих отношениях. Вот чистая возможность Bash. Трюк заключается в том, чтобы использовать exec соответствующим образом.

 #!/bin/bash (($#)) || set -- - while (($#)); do { [[ $1 = - ]] || exec < "$1"; } && while read -r; do printf '%s\n' "$REPLY" done shift done 

Имя файла доступно в $1 .

Если аргументы не заданы, мы искусственно устанавливаем - как первый позиционный параметр. Затем мы переходим к параметрам. Если параметр отсутствует, мы перенаправляем стандартный ввод из имени файла с помощью exec . Если это redirect удастся, мы зацикливаемся с циклом while. Я использую стандартную переменную REPLY , и в этом случае вам не нужно сбросить IFS . Если вы хотите другое имя, вы должны сбросить IFS так (если, конечно, вы этого не хотите и знаете, что вы делаете):

 while IFS= read -r line; do printf '%s\n' "$line" done 

Точнее…

 while IFS= read -r line ; do printf "%s\n" "$line" done < file 

Пожалуйста, попробуйте следующий код:

 while IFS= read -r line; do echo "$line" done < file 

Код ${1:-/dev/stdin} будет просто понимать первый аргумент, так что как насчет этого.

 ARGS='$*' if [ -z "$*" ]; then ARGS='-' fi eval "cat -- $ARGS" | while read line do echo "$line" done 

Следующее работает со стандартным sh (проверено dash на Debian) и вполне читаемо, но это вопрос вкуса:

 if [ -n "$1" ]; then cat "$1" else cat fi | commands_and_transformations 

Подробности: если первый параметр не пуст, то cat этот файл, иначе cat стандартный ввод. Затем вывод целого оператора if обрабатывается commands_and_transformations .

Я не считаю, что любые из этих ответов приемлемы. В частности, принятый ответ обрабатывает только первый параметр командной строки и игнорирует остальные. Программа Perl, которую он пытается эмулировать, обрабатывает все параметры командной строки. Поэтому принятый ответ даже не отвечает на вопрос. Другие ответы используют расширения bash, добавляют ненужные команды «cat», работают только для простого случая эхо ввода на выходе или просто излишне сложны.

Тем не менее, я должен отдать им кредит, потому что они дали мне некоторые идеи. Вот полный ответ:

 #!/bin/sh if [ $# = 0 ] then DEFAULT_INPUT_FILE=/dev/stdin else DEFAULT_INPUT_FILE= fi # Iterates over all parameters or /dev/stdin for FILE in "[email protected]" $DEFAULT_INPUT_FILE do while IFS= read -r LINE do # Do whatever you want with LINE here. echo $LINE done < "$FILE" done 

Как насчет

 for line in `cat`; do something($line); done - for line in `cat`; do something($line); done 
  • Чтение двоичных данных из std :: cin
  • Как читать строку с консоли в C?
  • nodejs, как читать нажатия клавиш от stdin
  • Как заставить ssh получить пароль от stdin
  • Обнаруживать, является ли stdin терминалом или трубой?
  • Как определить, была ли перенаправлена ​​Console.In (stdin)?
  • Запуск внешней программы с перенаправленным stdin и stdout из Java
  • Обманите приложение, думая, что его выступление - это терминал, а не труба
  • Чтение Eclipse stdin (System.in) из файла
  • Как читать из stdin по строкам в узле
  • Предоставить пароль SU в сценарии bash, в скрипте?
  • Interesting Posts

    Как программно печатать в PDF-файл без запроса имени файла в C # с помощью принтера Microsoft Print To PDF, который поставляется с Windows 10

    Генерировать hash из UIImage

    Как использовать распознавание речи google api в c #?

    AutoCompleteTextView, поддерживаемый CursorLoader

    Печать отладочной информации об ошибках с помощью java 8 lambda-выражений

    Как добавить reflection в приложение C ++?

    Сопоставление ключа с чем-то, что не на клавиатуре

    Как получить каталог из полного пути файла?

    Загрузите прямое streamовое видео с iPhone, например, Ustream или Qik

    Как изменить браузер по умолчанию в Yahoo! посыльный

    показать предупреждение в широковещательном приемнике после перезагрузки системы

    Mount дает неизвестный тип файловой системы 'vboxsf'

    Планирование повторяющейся задачи в Android

    1.4 ГБ электронной почты, Thunderbird все сообщения электронной почты пустые при открытии

    Node.js / Express.js – Как работает app.router?

    Давайте будем гением компьютера.