Следующий скрипт Perl ( my.pl
) может читать либо из файла в аргументах командной строки, либо из STDIN:
while (<>) {
print($_);
}
perl my.pl
будет читать из STDIN, а perl my.pl a.txt
будет читать изa.txt
. Это очень удобно.
Хотите знать, есть ли эквивалент в Bash?
/proc/$$/fd/0
и/dev/stdin
? Я заметил, что последнее кажется более распространенным и выглядит более простым.-r
к своейread
команде, чтобы она случайно не съела\
символы; использоватьwhile IFS= read -r line
для сохранения начальных и конечных пробелов./bin/sh
- вы используете оболочку, отличную отbash
илиsh
?Возможно, самое простое решение - перенаправить стандартный ввод с помощью оператора перенаправления слиянием:
Stdin - это нулевой дескриптор файла. Вышеприведенное посылает входные данные в ваш bash-скрипт в stdin less.
Узнайте больше о перенаправлении файловых дескрипторов .
источник
<&0
в этой ситуации не имеет смысла - ваш пример будет работать одинаково с ним или без него - по-видимому, инструменты, которые вы вызываете из скрипта bash по умолчанию, видят тот же stdin, что и сам скрипт (если скрипт не использует его первым).Вот самый простой способ:
Использование:
Чтобы назначить переменную stdin , вы можете использовать:
STDIN=$(cat -)
или просто, такSTDIN=$(cat)
как оператор не требуется (согласно комментарию @ mklement0 ).Чтобы проанализировать каждую строку из стандартного ввода , попробуйте следующий скрипт:
Для чтения из файла или стандартного ввода (если аргумент отсутствует), вы можете расширить его до:
Смотрите: Как читать stdin, когда аргументы не передаются? на стеке потока
источник
[ "$1" ] && FILE=$1 || FILE="-"
доFILE=${1:--}
. (Каламбур: лучше , чтобы избежать всех заглавных оболочки переменных в конфликт имен избежать с окружающей средой переменных.)${1:--}
это POSIX-совместимый, поэтому он должен работать во всех POSIX-подобных оболочках. То, что не будет работать во всех таких оболочках, это подстановка процесса (<(...)
); это будет работать в bash, ksh, zsh, но не в dash, например. Кроме того, лучше добавить-r
к вашейread
команде, чтобы она не случайно съела\
символы; готовьтесьIFS=
сохранить ведущие и конечные пробелы.echo
: если строка состоит из-e
,-n
или-E
, оно не будет показано. Чтобы исправить это, вы должны использоватьprintf
:printf '%s\n' "$line"
. Я не включал его в свое предыдущее редактирование… слишком часто мои исправления отменяются, когда я исправляю эту ошибку:(
.--
бесполезно, если первый аргумент'%s\n'
IFS=
сread
иprintf
вместоecho
.:)
,Я думаю, что это прямой путь:
-
-
источник
read
читает из стандартного ввода по умолчанию , так что нет никакой необходимости в< /dev/stdin
.echo
Решение добавляет новые строки всякий раз , когдаIFS
разбивает входной поток. Ответ @ fgm можно немного изменить:источник
read
«s поведение: в то время какread
это потенциально разделить на несколько лексем со стороны символов. содержащийся в нем$IFS
, он возвращает только один токен, если вы указываете только одно имя переменной (но по умолчанию обрезает начальные и конечные пробелы).read
и$IFS
-echo
сам добавляет новые строки без-n
флага. «Утилита echo записывает все указанные операнды, разделенные одиночными пустыми (` ') символами и сопровождаемые символом новой строки (`\ n'), в стандартный вывод."\n
добавить трейлингecho
: Perl$_
включает в себя строку, заканчивающуюся\n
прочитанной строкой, а bash -read
нет. (Однако, как указывает @gniourf_gniourf в другом месте, более надежный подход - использоватьprintf '%s\n'
вместоecho
).Цикл Perl в вопросе читает от всех аргументов имени файла в командной строке или из стандартного ввода, если файлы не указаны. Все ответы, которые я вижу, обрабатывают один файл или стандартный ввод, если файл не указан.
Несмотря на то, что его часто называют точно UUOC (Бесполезное использование
cat
), бывают моменты, когдаcat
это лучший инструмент для работы, и можно утверждать, что это один из них:Единственным недостатком этого является то, что он создает конвейер, работающий в под-оболочке, поэтому такие вещи, как присвоение переменных в
while
цикле, не доступны вне конвейера. Обходнойbash
путь - это замена процесса :Это оставляет
while
цикл работающим в основной оболочке, поэтому переменные, установленные в цикле, доступны вне цикла.источник
>>EOF\n$(cat "$@")\nEOF
. Наконец, придира:while IFS= read -r line
лучшее приближение к тому, чтоwhile (<>)
делает в Perl (сохраняет начальные и конечные пробелы - хотя Perl также сохраняет конечные\n
).Поведение Perl с кодом, приведенным в OP, может не принимать ни одного, ни нескольких аргументов, и если аргумент является одним дефисом,
-
это понимается как stdin. Кроме того, всегда можно иметь имя файла с$ARGV
. Ни один из ответов, данных до сих пор, в действительности не подражает поведению Perl в этих отношениях. Вот чистая возможность Bash. Хитрость заключается в том, чтобы использоватьexec
соответствующим образом.Имя файла доступно в
$1
.Если аргументы не указаны, мы искусственно устанавливаем
-
первый позиционный параметр. Затем мы зациклились на параметрах. Если параметр не-
, мы перенаправляем стандартный ввод из имени файла с помощьюexec
. Если это перенаправление прошло успешно, мыwhile
зациклимся. Я использую стандартнуюREPLY
переменную, и в этом случае вам не нужно сбрасыватьIFS
. Если вам нужно другое имя, вы должны сбросить егоIFS
так (если, конечно, вы этого не хотите и не знаете, что делаете):источник
Точнее...
источник
IFS=
и-r
кread
команде гарантирует, что каждая строка читается без изменений (включая начальные и конечные пробелы).Пожалуйста, попробуйте следующий код:
источник
read
безIFS=
и-r
, и бедного$line
без здоровых цитат.read -r
обозначения. ИМО, POSIX понял это неправильно; эта опция должна включать специальное значение для конечных обратных слешей, а не отключать его, чтобы существующие скрипты (до появления POSIX) не ломались, потому что-r
был опущен. Однако я замечаю, что это было частью IEEE 1003.2 1992 года, который был самой ранней версией стандарта оболочки и утилит POSIX, но даже тогда он был отмечен как дополнение, так что это вызывает недовольство давно ушедшими возможностями. Я никогда не сталкивался с неприятностями, потому что мой код не использует-r
; Мне должно быть повезло. Не обращай на это внимания.-r
должно быть стандартным. Я согласен, что это вряд ли произойдет в тех случаях, когда неиспользование этого приводит к проблемам. Тем не менее, неработающий код - это неработающий код. Мое редактирование было сначала вызвано этой плохой$line
переменной, которая сильно пропустила свои кавычки. Я исправил,read
пока я был на этом. Я не исправил,echo
потому что это вид редактирования, который откатывается.:(
,Код
${1:-/dev/stdin}
просто поймет первый аргумент, так что, как на счет этого?источник
Я не считаю ни один из этих ответов приемлемым. В частности, принятый ответ обрабатывает только первый параметр командной строки и игнорирует остальные. Программа Perl, которую она пытается эмулировать, обрабатывает все параметры командной строки. Таким образом, принятый ответ даже не отвечает на вопрос. Другие ответы используют расширения bash, добавляют ненужные команды 'cat', работают только для простого случая повторного ввода ввода в вывод или просто излишне сложны.
Тем не менее, я должен отдать им должное, потому что они дали мне некоторые идеи. Вот полный ответ:
источник
Я объединил все вышеперечисленные ответы и создал функцию оболочки, которая бы соответствовала моим потребностям. Это с терминала cygwin моих 2-х компьютеров с Windows10, где у меня была общая папка между ними. Я должен быть в состоянии справиться со следующим:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Если указано конкретное имя файла, мне нужно использовать то же имя файла во время копирования. Если поток входных данных был передан по каналу, то мне нужно создать временное имя файла с часами, минутами и секундами. Общая папка имеет подпапки дней недели. Это для организационных целей.
Вот лучший сценарий для моих нужд:
Если есть какой-то способ, который вы можете увидеть для дальнейшей оптимизации, я хотел бы знать.
источник
Следующее работает со стандартным
sh
(протестированоdash
на Debian) и вполне читабельно, но это дело вкуса:Подробности: если первый параметр не пустой, то
cat
этот файл, иначеcat
стандартный ввод. Затем вывод всегоif
оператора обрабатываетсяcommands_and_transformations
.источник
cat "${1:--}" | any_command
. Чтение переменных оболочки и их отображение могут работать для небольших файлов, но не так хорошо масштабируются.[ -n "$1" ]
Может быть упрощена[ "$1" ]
.Этот простой в использовании на терминале:
источник
Как насчет
источник
cat
будет помещен в командную строку. Командная строка имеет максимальный размер. Также это будет читать не построчно, а слово за словом.