Как мне прочитать несколько строк из STDIN в переменную?


24

Я гуглил этот вопрос безрезультатно. Я автоматизирую процесс сборки здесь, на работе, и все, что я пытаюсь сделать, это получить номера версий и крошечное описание сборки, которое может быть многострочным. Система, на которой это работает, - OSX 10.6.8.

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

попытки

read -d '' versionNotes

Приводит к искаженному вводу, если пользователь должен использовать клавишу возврата. Также нет хорошего способа завершить ввод, так как ^ D не завершает, а ^ C просто завершает процесс.

read -d 'END' versionNotes

Работает ... но все равно искажает ввод, если нужна клавиша возврата.

while read versionNotes
do
  echo "  $versionNotes" >> "source/application.yml"
done

Не правильно завершает ввод (потому что я слишком поздно, чтобы найти совпадения с пустой строкой).


Вы получаете эту информацию от пользователя, правильно?
Гленн Джекман

Правильный; Я хочу, чтобы пользователь вводил эту информацию в терминал при выполнении скрипта.
Роберт К

1
Вы не дали понять, я бы лучше сказал.
poige

Ответы:


20

man bash упоминает «…

Подстановка команд $ (cat file) может быть заменена эквивалентной, но более быстрой $ (<file).

... »

$ myVar=$(</dev/stdin)
hello
this is test
$ echo $myVar
hello this is test
$ echo "$myVar"
hello
this is test

и я согласен с тем, что стоит упомянуть - echo "$myVar"выглядело бы так, как было указано.


1
Как остановиться после многострочного ввода? Если я нажимаю Ctrl C, он останавливается, но переменная не сохраняется!
Нихил

2
Терминалы UNIX® имеют «дисциплину»: en.wikipedia.org/wiki/Line_discipline • Проверьте, что означает «eof» • Читайте man stty, узнайте, как получить текущие настройки
poige

2
Ctrl-D, чтобы остановить.
февраля

9

Попробуй это:

user@host:~$ read -d '' x <<EOF
> mic
> check
> one
> two
> EOF

Без разрывов строк:

user@host:~$ echo $x
mic check one two

С переносами строк:

user@host:~$ echo "$x"
mic
check
one
two

2
-d ''это именно то, что мне было нужно. Спасибо
Бруно Броноски

@ Бруно Мое удовольствие; это сложно. Особенно на первый взгляд это выглядит довольно стандартно. Это может быть весьма полезно, как только вы познакомитесь с различными особенностями.
голоса

8

Обратитесь к превосходному Руководству по Bash для всех ваших потребностей сценариев Bash.

В частности, Bash FAQ содержит это под номером 1:

Как я могу прочитать файл (поток данных, переменную) построчно (и / или поле за полем)?


Вы говорите, чтобы использовать read -r, но как мне получить это сделать из STDIN? Я попытаться использовать read -rна ранних стадиях.
Роберт К

Он читает из стандартного ввода по умолчанию.
Adaptr

2

Я решил эту проблему, работая с каждой строкой, пока не нашел пустую строку. Это работает достаточно хорошо для моей ситуации. Но если кто-то хочет добавить лучшее решение, не стесняйтесь делать это.

echo "---
notes: |" > 'version.yml'

while read line
do
  # break if the line is empty
  [ -z "$line" ] && break
  echo "  $line" >> "source/application.yml"
done

Используйте read -rвместо этого.
adaptr

2

Вы можете запустить редактор, как VIM, Pico ...

${VISUAL:-${EDITOR:-vi}} source/application.yml

Хм ... как это отвечает на вопрос ОП каким-либо образом?
adaptr

Он может запустить редактор из сценария.
Мирча Вутцовичи

И что именно это делает? Он хочет использовать текст из файла в сценарии, а не записывать информацию в файл.
Адаптер

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

1

Сначала несколько исправлений:

  1. Чтобы разрешить «издание» в строке, -eиспользуйте readline (так что у вас есть история bash и все функции редактирования)
  2. -dзанимает всего один символ. Например, из «END» берется «E», и всякий раз, когда пользователь пишет «E», чтение останавливается (я думаю, это не то, что вы хотите ...)

Есть несколько возможностей сделать это. Я бы прочитал строку за строкой и остановился бы, когда была найдена пустая строка (хотя вы могли бы установить любое слово остановки):

unset tmp
while :
do 
 read line
 [[ $line == "" ]] && tmp="${tmp:0:$((${#tmp}-1))}" && break
 tmp="$tmp"$line$'\n'
done

0

У вас есть несколько методов.

Один из самых простых методов:

MYVAR=$(yourcommand)
echo $"MYVAR"

Например:

MYVAR=$(ls /)
echo $"MYVAR"

За исключением того, что я не выполняю команду оболочки, как LS. Я запрашиваю многострочный ввод от пользователя.
Роберт К

Это очень плохая практика; не обрабатывать вывод ls!
Адаптер

@adaptr Мы слышали все это раньше, не могли бы вы предложить хорошую альтернативу, пожалуйста?
голоса

0

Мы используем конструкцию, использующую xargs и ctrl-d для взлома. Я не совсем доволен этим, но он, безусловно, выполняет работу по вводу многострочного пользовательского ввода и вставке его в переменную (форматирование не нарушено). (Первое и третье назначения добавляют кавычки вокруг содержимого ввода xargs.)

    printf "\\033[1mWhen finished hit ctrl-d on a new line to proceed.\\033[0m  \\n\\n" 
    # this will load the user's input into a variable instead of a file 
    reminderBody="\"" 
    reminderBody+=$( xargs -0 ) 
    reminderBody+="\"" 

В качестве темы сообщения электронной почты, отправляемого по почте (через bash), мы используем напоминание тела.


-1

Смотрите: http://tldp.org/LDP/abs/html/internal.html#READR.

Используйте readи обратите внимание, что если вы заканчиваете строку с \новой строки, игнорируется. Так что вы могли бы сделать:

#! / Bin / Баш

читать -p "версия:" версия
echo $ version

# введите некоторые входные данные и завершите длинные строки символом "\", затем введите обычный текст в конце
прочитайте -p "описание:" описание
echo -e "$ version \ n $ description >> yourfile.txt

Если бы я просто хотел, чтобы абзац с игнорированием разрывов строк, да. Но так как это сгенерированный список примечаний к выпуску для сценария сборки, я должен быть в состоянии сохранить эти разрывы строк; Я мог бы попытаться ввести маркированный список, например.
Роберт К

АБС - это чудовищное чудовищное выражение. 90% это просто неправильно.
adaptr

Это не что плохо.
голоса
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.