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

Вопрос или проблема

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

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

Попытки

read -d '' versionNotes

Результат — искажённый ввод, если пользователю нужно использовать клавишу backspace. Также нет хорошего способа завершить ввод, так как ^D не завершает его, а ^C просто завершает процесс.

read -d 'END' versionNotes

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

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

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

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" отобразила бы ввод так, как он был дан.

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

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

Обратитесь к отличному Bash Guide для всех ваших нужд в bash-сценариях.

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

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

Вы можете запустить редактор, такой как vim, pico…

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

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

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

while read line
do
  # прервать, если строка пуста
  [ -z "$line" ] && break
  echo "  $line" >> "source/application.yml"
done

~ $ txt=; while read line; do [[ $line == '.' ]] && break; txt+="$line\n"; done; txt=${txt:0:-2}
Hi! This should work, right?
Cheers!
.
~ $ echo $txt
Hi! This should work, right?
Cheers!
~ $

Это должно работать в zsh! 😃

txt=${txt:0:-2} – Чтобы удалить последний перевод строки.

P.S. Я думаю, эта функция прочитает многострочный ввод в переменную, названную как $1, переданную этой функции.

# например, 'readlines blaat' установит для $blaat многострочный ввод.
readlines() {
    eval "unset $1"
    while read line
    do
        [[ $line == '.' ]] && break
        eval "$1+='$line\n'"
    done
    eval "$1=\${$1:0:-2}"
}

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

  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

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

    printf '%s\n' "When finished hit ctrl-d on a new line to proceed.  " "" "" 
    # это загрузит ввод пользователя в переменную вместо файла 
    reminderBody="\"" 
    reminderBody+=$( xargs -0 ) 
    reminderBody+="\"" 

Мы используем reminderBody как тело электронной почты, отправляемой через mail (via bash).

Как говорится в вашем комментарии, ввод идет от пользователя через терминал: Вы можете использовать read для чтения многострочного ввода через

read -d $'\04' versionNotes

который устанавливает разделитель на EOF, который в Unicode является 0x04, так что вы можете читать ввод до тех пор, пока не будет дан CTRL-D.

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

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

MYVAR=$(yourcommand)
echo $"MYVAR"

Например:

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

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

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

#!/bin/bash

read -p "version: " version
echo $version

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

.

Ответ или решение

Чтение ввода из стандарта (STDIN) в переменную является одной из распространенных задач, с которой может столкнуться специалист по IT при автоматизации различных процессов, таких как сборка программного обеспечения. Проблема заключается в том, что пользовательский ввод может содержать несколько строк, и необходимо корректно их обработать и сохранить в переменную для последующего использования. Давайте рассмотрим несколько подходов к решению этой задачи, применимых в условиях операционной системы OSX 10.6.8.

Теория

Когда мы говорим о вводе данных из STDIN, важно помнить, что стандартный ввод — это поток ввода, который по умолчанию считывает данные из терминала. Один из базовых инструментов для работы с вводом в сценариях оболочки (shell) – это команда read. Однако команду read нужно уметь правильно применять, чтобы она могла обрабатывать многострочный ввод.

Важным моментом является определение маркера завершения ввода пользователем. В UNIX-подобных системах, таким маркером часто выступает комбинация клавиш Ctrl+D, которая посылает End Of Transmission (EOT), сигнализируя об окончании ввода.

Пример

На основе вашего описания, вы сталкиваетесь с проблемой получения чистого, не искаженного ввода, который пользователь может редактировать с помощью клавиши Backspace. Приведу пример решения на основе использования цикла while с командой read:

#!/bin/bash

echo "Введите описание версии (завершите ввод, введя пустую строку):"

versionNotes=""
while IFS= read -r line; do
    # Прерываем ввод, если строка пуста
    [ -z "$line" ] && break
    # Добавляем новую строку к переменной
    versionNotes+="$line"$'\n'
done

# Удаляем последнюю новую строку для корректного оформления результата
versionNotes="${versionNotes%$'\n'}"

echo "Ваш ввод:"
echo "$versionNotes"

Применение

В этом подходе:

  1. Команда read: Используется с флагом -r, который подавляет интерпретацию обратного слеша как экранирующего символа. Это полезно, если пользователь вводит символы, которые потенциально могут быть интерпретированы иначе.

  2. Цикл while: Продолжается до тех пор, пока пользователь не введет пустую строку, что используется как сигнал окончания ввода.

  3. Конкатенация строк: Используем встроенный символ $'\n' для добавления новой строки к переменной versionNotes.

  4. Результат: В конце убираем последнюю добавленную новую строку, что позволяет избежать лишнего пустого строкового символа в выводе.

Этот механизм позволяет пользователю вводить многострочный текст с возможностью редактирования, а также определяет окончание ввода через ввод пустой строки. Таким образом, данный скрипт эффективно решает вашу задачу, обеспечивая корректное сохранение данных.

Дополнительные рекомендации

  • Документация: Регулярное обращение к документации и справочным ресурсам может существенно облегчить процесс написания скриптов. Например, изучение руководств по Bash, таких как Bash Guide, расширит ваше понимание шелл-скриптинга.

  • Редакторы: Используйте возможности современных текстовых редакторов для редактирования source/application.yml. Как было упомянуто, запуск редактора через переменные среды ${VISUAL:-${EDITOR:-vi}} может обеспечить более управляемый процесс редактирования.

  • Ввод-вывод: Всегда тестируйте скрипты на небольших примерах, прежде чем внедрять их в рабочие процессы. Это поможет избежать ошибок и упрощает отладку кода.

Итак, предложенный подход позволяет гибко работать с пользовательским многострочным вводом в сценариях автоматизации под ОС OSX. Надеюсь, это решение поможет оптимизировать ваш рабочий процесс сборки.

Оцените материал
Добавить комментарий

Капча загружается...