Захват вывода нескольких строк в переменную Bash

У меня есть script 'myscript', который выводит следующее:

abc
def
ghi

в другом script, я вызываю:

declare RESULT=$(./myscript)

и $RESULT получает значение

abc def ghi

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

Ответ 1

Фактически, RESULT содержит то, что вы хотите - продемонстрировать:

echo "$RESULT"

То, что вы показываете, это то, что вы получаете от:

echo $RESULT

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

Ответ 2

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

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

Это особенно важно, если вы хотите обрабатывать все возможные имена файлов (чтобы избежать поведения undefined, как работа с неправильным файлом).

Ответ 3

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

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

Ответ 4

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

declare RESULT=($(./myscript))  # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"

Ответ 5

Как насчет этого, он будет читать каждую строку переменной и которая может быть использована впоследствии! например, вывод myscript перенаправляется в файл с именем myscript_output

awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'

Ответ 6

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

./myscript.sh > /tmp/foo
while read line ; do 
    echo 'whatever you want to do with $line'
done < /tmp/foo

Быстрый взломать, чтобы сделать требуемое действие:

result=""
./myscript.sh > /tmp/foo
while read line ; do
  result="$result$line\n"
done < /tmp/foo
echo -e $result

Обратите внимание, что добавлена ​​дополнительная строка. Если вы работаете над ней, вы можете ее кодировать, я просто слишком ленив.


РЕДАКТИРОВАТЬ: Хотя этот случай работает отлично, люди, читающие это, должны знать, что вы можете легко сквозировать свой stdin внутри цикла while, тем самым предоставляя вам script, который будет запускать одну строку, очистить stdin и выйти. Как ssh будет делать это, я думаю? Я недавно это видел, другие примеры кода здесь: https://unix.stackexchange.com/info/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, как и фактическое имя файла. Наверное, здесь не нужно объяснять, но кто-то жаловался на комментарии.