У меня есть bash script, который вызывает несколько длительных процессов. Я хочу записать вывод этих вызовов в переменные для обработки. Однако, поскольку это длительные процессы, я хотел бы, чтобы вывод вызовов rsync отображался в консоли в режиме реального времени, а не после факта.
С этой целью я нашел способ сделать это, но он полагается на вывод текста в /dev/stderr. Я чувствую, что вывод в /dev/stderr - не лучший способ сделать что-то.
VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee /dev/stderr)
VAR2=$(rsync -r -t --out-format='%n%L' --delete -s /path/source1/ /path/target1 | tee /dev/stderr)
VAR3=$(rsync -r -t --out-format='%n%L' --delete -s /path/source2/ /path/target2 | tee /dev/stderr)
В приведенном выше примере я вызываю rsync несколько раз, и я хочу видеть имена файлов по мере их обработки, но в конце я все еще хочу получить результат в переменной, потому что я буду разбирать его позже.
Есть ли "более чистый" способ сделать это?
Если это имеет значение, я использую Ubuntu 12.04, bash 4.2.24.
Дублируйте & 1 в своей оболочке (в моем примере до 5) и используйте & 5 в подоболочке (так что вы будете писать в stdout (& 1) родительской оболочки):
exec 5>&1
FF=$(echo aaa|tee >(cat - >&5))
echo $FF
Будет печатать aaa два раза, из-за эха в подоболочке и второй раз печатать значение переменной.
В вашем коде:
exec 5>&1
VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee >(cat - >&5))
# use the value of VAR1
Ответ Op De Cirkel имеет правильную идею. Его можно упростить еще больше (избегая использования cat
):
exec 5>&1
FF=$(echo aaa|tee /dev/fd/5)
echo $FF
tee /dev/fd/1
, но это не работает, потому что вывод по-прежнему захватывается $()
. Таким образом , в случае , если кто - то будет интересно , то же самое, что необходимо использовать дополнительный дескриптор файла (например , 5).
Здесь пример, содержащий как stderr
, так и код выхода команды. Это строится на ответе Рассела Дэвиса.
exec 5>&1
FF=$(ls /taco/ 2>&1 |tee /dev/fd/5; exit ${PIPESTATUS[0]})
exit_code=$?
echo "$FF"
echo "Exit Code: $exit_code"
Если папка /taco/
существует, это будет захватывать ее содержимое. Если папка не существует, она будет отображать сообщение об ошибке, а код выхода будет равен 2.
Если вы опустите 2>&1
, тогда будет снято только stdout
.
Вы можете использовать более трех дескрипторов файлов. Попробуйте здесь:
http://tldp.org/LDP/abs/html/io-redirection.html
"Каждому открытому файлу присваивается дескриптор файла. [2] Дескрипторы файла для stdin, stdout и stderr равны 0, 1 и 2. Соответственно, для открытия дополнительных файлов остаются дескрипторы с 3 по 9. Это иногда полезно назначить один из этих дополнительных файловых дескрипторов для stdin, stdout или stderr как временную дублируемую ссылку.
Суть в том, стоит ли сделать script более сложным только для достижения этого результата. На самом деле это не совсем так, как вы это делаете.