Сохранение многоточечных выводов в переменную Bash
Я создал скрипт 'myscript', который выводит следующее:
abc
def
ghi
В другом скрипте я вызываю:
declare RESULT=$(./myscript)
В результате переменная $RESULT
принимает значение:
abc def ghi
Существует ли способ сохранить результат либо с символами новой строки, либо с символом '\n', чтобы я мог вывести его с помощью echo -e
?
5 ответ(ов)
На самом деле, RESULT
содержит то, что вам нужно — для демонстрации:
echo "$RESULT"
То, что вы показываете, это результат команды:
echo $RESULT
Как отмечено в комментариях, разница заключается в том, что (1) версия с двойными кавычками (echo "$RESULT"
) сохраняет внутренние пробелы значения точно так, как они представлены в переменной — включая переносы строк, табуляции и множественные пробелы — в то время как (2) некорректная версия без кавычек (echo $RESULT
) заменяет каждую последовательность одного или более пробелов, табуляций и переносов строк на один пробел. Таким образом, (1) сохраняет структуру входной переменной, тогда как (2) создает потенциально очень длинную строку вывода, где 'слова' отделены одиночными пробелами (при этом 'слово' — это последовательность символов, не являющихся пробелами; в словах не обязательно должны присутствовать буквенно-цифровые символы).
Если вас интересуют конкретные строки, вы можете использовать массив результатов:
declare RESULT=($(./myscript)) # (..) = массив
echo "Первая строка: ${RESULT[0]}"
echo "Вторая строка: ${RESULT[1]}"
echo "N-я строка: ${RESULT[N]}"
Этот подход позволяет вам хранить выходные данные скрипта в массиве, что делает доступ к отдельным строкам более удобным. Не забудьте заменить N
на индекс нужной строки.
В дополнение к ответу пользователя @l0b0, у меня была ситуация, когда мне нужно было сохранить любые завершающие символы новой строки, выводимые скриптом, и проверить код возврата скрипта. Проблема с ответом l0b0 заключается в том, что команда 'echo x' сбрасывала $? обратно на ноль... поэтому я смог придумать довольно хитроумное решение:
RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"
Таким образом, переменная RETURNCODE
будет содержать код возврата вашего скрипта, а переменная RESULT
будет содержать вывод скрипта с сохранением завершающих символов новой строки.
После того как я перепробовал большинство решений, предложенных здесь, я пришёл к очевидному - проще всего использовать временный файл. Не совсем уверен, что именно вы хотите сделать с вашим многострочным выводом, но затем можно обрабатывать его построчно с помощью команды read
. Единственное, что вы не сможете сделать легко - это сложить всё в одну переменную, но для большинства практических целей такой подход значительно проще.
./myscript.sh > /tmp/foo
while read line ; do
echo 'что угодно с $line'
done < /tmp/foo
Вот простой способ выполнить запрашиваемое действие:
result=""
./myscript.sh > /tmp/foo
while read line ; do
result="$result$line\n"
done < /tmp/foo
echo -e $result
Обратите внимание, что это добавляет лишнюю строку. Если поработать над этим, можно обойтись без нее, но мне просто лениво.
EDIT: Хотя этот способ отлично работает, людям, читающим это, следует помнить, что вы можете легко "подавить" стандартный ввод внутри цикла while
, что приводит к скрипту, который обрабатывает одну строчку, очищает stdin и завершает выполнение. Например, так делает ssh
, если я не ошибаюсь? Я только что это заметил, вот другие примеры кода: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while
Еще раз! На этот раз с другим дескриптором файла (stdin, stdout, stderr - это 0-2, так что мы можем использовать &3 или выше в bash).
result=""
./test > /tmp/foo
while read line <&3; do
result="$result$line\n"
done 3</tmp/foo
echo -e $result
Вы также можете использовать mktemp
, но это просто быстрый пример кода. Использование mktemp
выглядит следующим образом:
filenamevar=`mktemp /tmp/tempXXXXXX`
./test > $filenamevar
А затем используйте $filenamevar
, как если бы это было реальное имя файла. Думаю, объяснять это здесь не нужно, но кто-то уже пожаловался в комментариях.
Ваш код использует команду awk
для чтения каждой строки из файла myscript_output
и сохранения ее в переменной var
, а затем выводит каждую строку на экран. Однако, есть несколько моментов, которые стоит учесть.
Во-первых, вы открываете файл myscript_output
внутри цикла, что не является хорошей практикой. Лучше открыть файл один раз перед началом цикла, а затем просто использовать getline
для чтения строк.
Вот улучшенная версия вашего кода:
awk '{
while (getline var < "myscript_output") {
print var;
}
close("myscript_output");
}' # конец awk
Таким образом, код будет сначала считывать строки из myscript_output
и выводить их, сохраняя каждую строку в переменной var
. Также не забудьте, что если вы хотите использовать эту переменную в дальнейшем (например, за пределами awk
), вам понадобится сохранить её в каком-то внешнем формате, так как переменные, определенные внутри awk
, не доступны за его пределами.
Обратите внимание на то, что вызов close("myscript_output")
не обязателен в данном случае, так как файл будет закрыт автоматически в конце работы скрипта awk
. Вы можете оставить его, если хотите иметь явный контроль над открытыми файлами.
Как проверить, установленна ли переменная в Bash
Установить переменные окружения из файла с парами ключ/значение
Создание переменной временной метки в bash-скрипте
Извлечение имени файла и расширения в Bash
Как получить пароль из оболочки без вывода в терминал?