як вивести текст як на екран, так і в файл у скрипті оболонки?


49

В даний час у мене є сценарій оболонки, який записує повідомлення до файлу журналу, як це:

log_file="/some/dir/log_file.log"
echo "some text" >> $log_file
do_some_command
echo "more text" >> $log_file
do_other_command

Під час виконання цього сценарію виводу на екран немає, і, оскільки я підключаюсь до сервера за допомогою putty, я повинен відкрити інше з'єднання і зробити "tail -f log_file_path.log", тому що я не можу припинити виконання скрипт, і я хочу побачити результат у режимі реального часу.

Очевидно, що я хочу, щоб текстові повідомлення друкувалися на екрані та у файл, але я хотів би зробити це в одному рядку, а не в двох рядках, в одному з яких немає перенаправлення на файл.

Як цього досягти?

Відповіді:


71

Це працює:

command | tee -a "$log_file"

teeзберігає вхід у файл (використовувати -aдля додавання, а не для перезапису), а також копіює вхід на стандартний вихід.


8

Ви можете використовувати тут-doc та. джерело його для ефективної, POSIX-зручної загальної колекторної моделі.

. 8<<-\IOHERE /proc/self/fd/8

command
 
fn() { declaration ; } <<WHATEVER
# though a nested heredoc might be finicky
# about stdin depending on shell
WHATEVER
cat -u ./stdout | ./works.as >> expect.ed
IOHERE

Коли ви відкриваєте heredoc, ви надсилаєте сигнал оболонці за допомогою вхідного маркера IOHERE про те, що вона повинна перенаправляти свій вхід до вказаного вами дескриптора файлу, поки він не зустріне інший кінець вашого маркера обмежувача. Я оглянувся, але не побачив багатьох прикладів використання номера fd перенаправлення, як я показав вище в поєднанні з оператором heredoc, хоча його використання чітко визначено в основних вказівках командної оболонки POSIX. Більшість людей просто вказують це на stdin і знімають, але я вважаю, що джерела пошуку джерел цього способу можуть утримати безкоштовно stdin, а складові програми не скаржаться на заблоковані шляхи вводу / виводу.

Вміст heredoc передається у вказаний вами дескриптор файлу, який, в свою чергу, потім інтерпретується як оболонка і виконується. вбудований, але не без вказання конкретного шляху для. . Якщо шлях / proc / self створює проблеми, спробуйте / dev / fd / n або / proc / $$. Цей же метод працює на трубах, до речі:

cat ./*.sh | . /dev/stdin

Напевно, принаймні так нерозумно, як це виглядає. Зрозуміло, ви можете зробити те ж саме з sh, але його мета - виконати в поточному середовищі оболонки, що, мабуть, те, що ви хочете, і, залежно від оболонки, набагато більше шансів працювати з гередоком, ніж зі стандартною анонімною трубкою.

У будь-якому випадку, як ви, напевно, помітили, я досі не відповів на ваше запитання. Але якщо ви думаєте про це, таким же чином гередок передає весь ваш код до., Він також надає вам єдину, просту, точку зору:

. 5<<EOIN /dev/fd/5 |\ 
    tee -a ./log.file | cat -u >$(tty)
script
 
more script
EOIN

Таким чином, вся термінальна stdout з будь-якого коду, виконаного у вашому heredoc, виводиться звідти. як правило, і їх можна легко відірвати від однієї труби. Я включив нерозподілений виклик кішки, тому що мені незрозуміло поточний напрямок stdout, але його, ймовірно, надлишковим (майже напевно це так, як це написано у будь-якому випадку), і трубопровід, можливо, може закінчитися прямо в трійку.

Ви також можете поставити під сумнів відсутню цитату зворотної косої риски у другому прикладі. Цю частину важливо зрозуміти перед тим, як скористатися, і може дати вам декілька ідей про те, як її використовувати. Цитований обмежувач гередока (до цих пір ми використовували IOHERE та EOIN, і перший, який я цитував із зворотним косою рисою, хоча "одиничні" або "подвійні" лапки будуть служити тій самій цілі), заборонить оболонці виконувати будь-яке розширення параметрів на вмісту, але без котирування обмежувач залишить його вміст відкритим для розширення. Наслідки цього, коли є ваш гередок. Драматичні:

. 3<<HD ${fdpath}/3
: \${vars=$(printf '${var%s=$((%s*2))},' `seq 1 100`)} 
HD
echo $vars
> 4,8,12 
echo $var1 $var51
> 4 104

Оскільки я не цитував обмежувач гередока, оболонка розширила вміст під час його читання і до подачі дескриптору отриманого файлу. виконати. Це, по суті, призвело до того, що команди були проаналізовані двічі - розгортаються. Оскільки я зворотній косий ривок цитував розширення параметра $ vars, оболонка проігнорувала його декларацію при першому проході і лише позбавила зворотної косої риси, щоб весь вміст розширеного printf міг бути оцінений нулем, коли. Сценарій знайшов у другому проході.

Ця функціональність - це саме те, що може забезпечити вбудована небезпечна оболонка eval, навіть якщо з цитуванням набагато простіше обробляти гередок, ніж з eval, і може бути однаково небезпечним. Якщо ви не плануєте це ретельно, мабуть, найкраще цитувати обмежувач "EOF" як звичку. Просто кажу.

РЕДАКЦІЯ: Е, я озираюся на це і думаю, що це трохи надто розтягнення. Якщо ВСЕ вам потрібно зробити, це об'єднати кілька виходів в одну трубу, то найпростішим методом є лише використання:

{ or ( command ) list ; } | tee -a ea.sy >>pea.sy

Кучері намагаються запустити вміст у поточній оболонці, тоді як пароні автоматично відключаються. І все-таки кожен може сказати вам це і, принаймні, на мою думку, своє. Рішення heredoc набагато більш цінна інформація, особливо якщо ви хочете зрозуміти, як оболонка насправді працює.

Веселіться!


3

Я знайшов цю відповідь, шукаючи зміни сценарію встановлення для запису журналу встановлення.

Мій сценарій вже наповнений ехо-заявами на кшталт:

echo "Found OLD run script $oldrunscriptname"
echo "Please run OLD tmunsetup script first!"

І я не хотів, щоб запустити його за допомогою типового оператора (або іншого сценарію для виклику існуючого з трійником), тому я написав це:

#!/bin/bash
# A Shell subroutine to echo to screen and a log file

LOGFILE="junklog"

echolog()
(
echo $1
echo $1 >> $LOGFILE
)


echo "Going"
echolog "tojunk"

# eof

Тож тепер у моєму оригінальному сценарії я можу просто змінити 'echo' на 'echolog', де я хочу вивести файл журналу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.