7

Сохранение многоточечных выводов в переменную Bash

2

Я создал скрипт 'myscript', который выводит следующее:

abc
def
ghi

В другом скрипте я вызываю:

declare RESULT=$(./myscript)

В результате переменная $RESULT принимает значение:

abc def ghi

Существует ли способ сохранить результат либо с символами новой строки, либо с символом '\n', чтобы я мог вывести его с помощью echo -e?

5 ответ(ов)

13

На самом деле, RESULT содержит то, что вам нужно — для демонстрации:

echo "$RESULT"

То, что вы показываете, это результат команды:

echo $RESULT

Как отмечено в комментариях, разница заключается в том, что (1) версия с двойными кавычками (echo "$RESULT") сохраняет внутренние пробелы значения точно так, как они представлены в переменной — включая переносы строк, табуляции и множественные пробелы — в то время как (2) некорректная версия без кавычек (echo $RESULT) заменяет каждую последовательность одного или более пробелов, табуляций и переносов строк на один пробел. Таким образом, (1) сохраняет структуру входной переменной, тогда как (2) создает потенциально очень длинную строку вывода, где 'слова' отделены одиночными пробелами (при этом 'слово' — это последовательность символов, не являющихся пробелами; в словах не обязательно должны присутствовать буквенно-цифровые символы).

0

Если вас интересуют конкретные строки, вы можете использовать массив результатов:

declare RESULT=($(./myscript))  # (..) = массив
echo "Первая строка: ${RESULT[0]}"
echo "Вторая строка: ${RESULT[1]}"
echo "N-я строка: ${RESULT[N]}"

Этот подход позволяет вам хранить выходные данные скрипта в массиве, что делает доступ к отдельным строкам более удобным. Не забудьте заменить N на индекс нужной строки.

0

В дополнение к ответу пользователя @l0b0, у меня была ситуация, когда мне нужно было сохранить любые завершающие символы новой строки, выводимые скриптом, и проверить код возврата скрипта. Проблема с ответом l0b0 заключается в том, что команда 'echo x' сбрасывала $? обратно на ноль... поэтому я смог придумать довольно хитроумное решение:

RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"

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

0

После того как я перепробовал большинство решений, предложенных здесь, я пришёл к очевидному - проще всего использовать временный файл. Не совсем уверен, что именно вы хотите сделать с вашим многострочным выводом, но затем можно обрабатывать его построчно с помощью команды 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, как если бы это было реальное имя файла. Думаю, объяснять это здесь не нужно, но кто-то уже пожаловался в комментариях.

0

Ваш код использует команду 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. Вы можете оставить его, если хотите иметь явный контроль над открытыми файлами.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь