Как прочитать множественный ввод из stdin в переменную и как распечатать его в shell (sh, bash)?
Вопрос
То, что я хочу сделать, это следующее:
- считывание в многострочном вводе из
stdin
в переменнуюA
- выполняйте различные операции над
A
- труба
A
без потери символов - разделителей (\n
,\r
,\t
, и т.д.) к другой команде
Текущая проблема заключается в том, что я не могу прочитать это с помощью read
команда, потому что она прекращает чтение при переводе строки.
Я могу читать стандартный код с помощью cat
, вот так:
my_var=`cat /dev/stdin`
, но тогда я не знаю, как это напечатать.Так что перевод строки, табуляция и другие разделители все еще присутствуют.
Мой пример скрипта выглядит примерно так:
#!/usr/local/bin/bash
A=`cat /dev/stdin`
if [ ${#A} -eq 0 ]; then
exit 0
else
cat ${A} | /usr/local/sbin/nextcommand
fi
Решение
Это работает для меня:
myvar=`cat`
echo "$myvar"
Цитаты вокруг $myvar
важны.
Другие советы
В Bash есть альтернативный способ; man bash
упоминает:
Подстановка команд
$(cat file)
может быть заменена эквивалентной, но более быстрой$(< file)
.
$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
тройник выполняет свою работу
#!/bin/bash
myVar=$(tee)
Да, это работает и для меня. Спасибо.
myvar=`cat`
совпадает с
myvar=`cat /dev/stdin`
Ну да. Со страницы руководства bash
:
Заключение символов в двойные кавычки сохраняет буквальную ценность всех символы в кавычках, за исключением $, `, \, и, когда расширение истории включен,! Символы $ и ` сохранить их особое значение в двойных кавычках.
Если вы заботитесь о сохранении завершающих символов новой строки в конце выходных данных, используйте это:
myVar=$(cat; echo x)
myVar=${myVar%x}
printf %s "$myVar"
Здесь используется трюк из здесь .
[обновлено]
Это назначение будет зависать бесконечно, если в канале ничего нет...
var="$(< /dev/stdin)"
Однако мы можем предотвратить это, установив тайм-аут read
для первого символа.Если время ожидания истекло, код возврата будет больше 128, и мы узнаем канал STDIN (он же /dev/stdin
) пусто.
В противном случае мы получим остальную часть STDIN by...
- настройка
IFS
обнулить только дляread
команда - отключение экранирования с помощью
-r
- устранение разделителя чтения с помощью
-d ''
. - и, наконец, добавим это к символу, который мы получили изначально
Таким образом...
__=""
_stdin=""
read -N1 -t1 __ && {
(( $? <= 128 )) && {
IFS= read -rd '' _stdin
_stdin="$__$_stdin"
}
}
Этот метод позволяет избежать использования var="$(command ...)"
Замена команды, которая, по замыслу, всегда удаляет все завершающие символы новой строки.
Если предпочтительна подстановка команд, чтобы сохранить завершающие символы перевода строк, мы можем добавить один или несколько символов-разделителей к выходным данным внутри $()
а затем снимите их снаружи.
Например ( примечание $(parens)
в первой команде и ${braces}
во втором )...
_stdin="$(awk '{print}; END {print "|||"}' /dev/stdin)"
_stdin="${_stdin%|||}"