Захват нескольких строк вывода в переменную Bash
у меня есть скрипт 'myscript', который выводит следующее:
abc
def
ghi
в другом скрипте я называю:
declare RESULT=$(./myscript)
и $RESULT получает значение
abc def ghi
есть ли способ сохранить результат либо с новыми строками, либо с символом 'n', чтобы я мог вывести его с помощью'echo -e'?
6 ответов:
на самом деле, результат содержит то, что вы хотите - продемонстрировать:
echo "$RESULT"то, что вы показываете, это то, что вы получаете от:
echo $RESULT
как отмечалось в комментариях, разница заключается в том, что (1) версия переменной в двойных кавычках (
echo "$RESULT") сохраняет внутренний интервал значения точно так, как он представлен в переменной-новые строки, вкладки, несколько пробелов и все-тогда как (2) некотируемая версия (echo $RESULT) заменяет каждую последовательность из одного или более пробелов, табуляций и строки с пробелом. Таким образом, (1) сохраняет форму входной переменной, тогда как (2) создает потенциально очень длинную единственную строку вывода со словами, разделенными одиночными пробелами (где "слово" -это последовательность символов без пробелов; в любом из слов не должно быть буквенно-цифровых символов).
еще одна ловушка с этим является то, что команду -
$()- полоски замыкающие строки. Наверное, не всегда важно, но если вы действительно хотите сохранить ровно что было выведено, вам придется использовать другую строку и некоторые цитаты:RESULTX="$(./myscript; echo x)" RESULT="${RESULTX%x}"Это особенно важно, если вы хотите дескриптор все возможные имена (чтобы избежать неопределенного поведения, такого как работа с неправильным файлом).
в дополнение к ответу, данному @l0b0, у меня просто была ситуация, когда мне нужно было сохранить любые конечные новые строки, выводимые скриптом и проверьте код возврата скрипта. И проблема с ответом l0b0 заключается в том, что "echo x" сбрасывал $? назад к нулю... так что мне удалось придумать это очень хитрое решение:
RESULTX="$(./myscript; echo x$?)" RETURNCODE=${RESULTX##*x} RESULT="${RESULTX%x*}"
в случае, если вы заинтересованы в конкретных линий, использовать результирующий массив:
declare RESULT=($(./myscript)) # (..) = array echo "First line: ${RESULT[0]}" echo "Second line: ${RESULT[1]}" echo "N-th line: ${RESULT[N]}"
Как насчет этого, он будет читать каждую строку в переменную, и это может быть использовано впоследствии ! скажем, вывод myscript перенаправляется в файл с именем myscript_output
awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'
после того, как я попробовал большинство решений здесь, самое простое, что я нашел, было очевидным - использование временного файла. Я не уверен, что вы хотите сделать с вашим многострочным выходом, но вы можете справиться с ним по строкам, используя чтение. Единственное, что вы не можете сделать, это легко вставить все это в одну и ту же переменную, но для большинства практических целей это намного проще.
./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обратите внимание на это добавляет дополнительную строку. Если вы работаете над этим, вы можете кодировать вокруг него, я просто слишком ленив.
EDIT: хотя этот случай работает отлично, люди, читающие это, должны знать, что вы можете легко раздавить свой stdin внутри цикла 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, как вы бы фактическое имя файла. Наверное, не нужно объяснил здесь, но кто-то жаловался в комментариях.
Comments