Як я читаю кілька рядків зі 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

Не належним чином закінчується введення даних (тому що я занадто пізно шукаю відповідність проти порожнього рядка).


Ви отримуєте цю інформацію від користувача, правда?
glenn jackman

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

1
Ви не дали зрозуміти, я б сказала.
poige

Відповіді:


20

man bash згадує «…

Заміна команди $ (файл cat) може бути замінена на еквівалентний, але швидший $ (<файл).

… »

$ 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 ''саме те, що мені було потрібно. Спасибі
Бруно Броноскі

@Bruno Моє задоволення; це хитро. Особливо на перший погляд, це виглядає досить стандартно. Це може бути дуже корисним, як тільки ви отримаєте повісити різні ідіосинкразії.
голоси

8

Зверніться до відмінного керівництва Bash для всіх ваших потреб в сценаріях на баш.

Зокрема, FAQ Bash містить це під номером №1:

Як я можу прочитати файл (потік даних, змінний) по черзі (та / або поле за полем)?


Ви кажете використовувати read -r, але як я можу це зробити від STDIN? Я намагався використовувати read -rрано.
Роберт К

Він читається з stdin за замовчуванням.
адаптер

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замість цього.
адаптор

2

Ви можете запустити такий редактор, як vim, pico ...

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

Гм ... як це взагалі відповідає на питання ОП?
адаптер

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

І що саме досягає цього? Він хоче використовувати текст із файлу в сценарії, а не записувати інформацію у файл.
адаптер

Він не хоче прочитати текст від користувача і записати його у файл. Прочитайте коментарі, додані до питання.
Мірча Вутковичі

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+="\"" 

Ми використовуємо ReminderBody як предмет електронної пошти, що надсилається поштою (через bash).


-1

Дивіться: http://tldp.org/LDP/abs/html/internal.html#READR

Використовуйте readта зауважте, що якщо ви закінчите рядок з \новою лінією, це ігнорується. Отже, ви можете зробити:

#! / бін / баш

версія-read "version:"
версія echo $

# введіть кілька вхідних та кінцевих довгих рядків з "\", а потім введіть звичайний кінець
read -p "description:" Опис
echo -e "$ версія \ n $ опис >> yourfile.txt

Якщо я просто хотів ігнорувати абзац з розривами рядків, так. Але оскільки це генерований список нотаток до випуску для сценарію збірки, мені потрібно вміти зберігати ці розриви рядків; Я можу спробувати увійти, наприклад, у маркований список.
Роберт К

АБС - це чудовисько жахливих розмірів. 90% це явно неправильно.
адаптор

Це не що погано.
голоси
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.