Ben nasıl kullanılacağını bilmek tee
çıkışını (yazmak için STDOUT
bir) aaa.sh
için bbb.out
hala Terminalde bunu görüntülenirken,:
./aaa.sh | tee bbb.out
Şimdi görüntülenirken, şimdi STDERR
adlı bir dosyaya nasıl yazabilirim ccc.out
?
Ben nasıl kullanılacağını bilmek tee
çıkışını (yazmak için STDOUT
bir) aaa.sh
için bbb.out
hala Terminalde bunu görüntülenirken,:
./aaa.sh | tee bbb.out
Şimdi görüntülenirken, şimdi STDERR
adlı bir dosyaya nasıl yazabilirim ccc.out
?
Yanıtlar:
Terminalde hala STDERR ve STDOUT'u görmek istediğinizi varsayıyorum. Josh tail
Kelley'in cevabı için gidebilirsin, ama günlük dosyanızı çok hackish ve cludgy çıktısı arka planda tutmak . Bir exra FD tutmanız ve daha sonra onu öldürerek temizleme yapmanız gerektiğine dikkat edin ve teknik olarak bunu a trap '...' EXIT
.
Bunu yapmanın daha iyi bir yolu var ve bunu zaten keşfettiniz: tee
.
Sadece, stdout için kullanmak yerine, stdout için bir tee ve stderr için bir tane var. Bunu nasıl başaracaksınız? Süreç ikamesi ve dosya yönlendirmesi:
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
Hadi bölelim ve açıklayalım:
> >(..)
>(...)
(işlem ikamesi) bir FIFO oluşturur ve tee
dinlemenizi sağlar . Ardından, >
STDOUT öğesinin command
ilkini tee
dinlediği FIFO'ya yönlendirmek için (dosya yönlendirme) kullanır .
İkincisi için aynı şey:
2> >(tee -a stderr.log >&2)
tee
STDIN'den okunan ve onu içine alan bir işlem yapmak için süreç ikamesini tekrar kullanırız stderr.log
. tee
girişini tekrar STDOUT'a gönderir, ancak girişi tee
STDERR'ımız olduğu için STDOUT'u tekrar STDERR'ımıza yönlendirmek isteriz. Daha sonra command
STDERR dosyasını FIFO'nun girişine ( tee
'STDIN) yönlendirmek için dosya yeniden yönlendirmesini kullanırız .
Bkz. Http://mywiki.wooledge.org/BashGuide/InputAndOutput
Süreç ikamesi, (POSIX veya Bourne) bash
yerine mermi olarak seçme bonusu olarak elde ettiğiniz gerçekten güzel şeylerden biridir sh
.
İçinde sh
, işleri manuel olarak yapmanız gerekir:
out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee -a stdout.log < "$out" &
tee -a stderr.log < "$err" >&2 &
command >"$out" 2>"$err"
$ echo "HANG" > >(tee stdout.log) 2> >(tee stderr.log >&2)
işe yarıyor, ama girişi bekliyor. Bunun olmasının basit bir nedeni var mı?
/bin/bash 2> err
ve/bin/bash -i 2> err
(echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
neden sadece:
./aaa.sh 2>&1 | tee -a log
Bu basitçe yönlendirir stderr
için stdout
, tee yankıları böylece hem log ve ekrana etmek. Belki bir şeyleri kaçırıyorum, çünkü diğer çözümlerin bazıları gerçekten karmaşık görünüyor.
Not: bash sürüm 4'ten beri aşağıdakiler için |&
bir kısaltma olarak kullanabilirsiniz 2>&1 |
:
./aaa.sh |& tee -a log
./aaa.sh |& tee aaa.log
çalışır (bash).
set -o pipefail
sonrasında gelen ;
ya &&
da yanılmıyorsam çıkış durumunu koruyabileceğinize inanıyorum .
Bu, bunu google üzerinden bulan kullanıcılar için yararlı olabilir. Sadece denemek istediğiniz örneği açın. Tabii ki, çıktı dosyalarını yeniden adlandırmaktan çekinmeyin.
#!/bin/bash
STATUSFILE=x.out
LOGFILE=x.log
### All output to screen
### Do nothing, this is the default
### All Output to one file, nothing to the screen
#exec > ${LOGFILE} 2>&1
### All output to one file and all output to the screen
#exec > >(tee ${LOGFILE}) 2>&1
### All output to one file, STDOUT to the screen
#exec > >(tee -a ${LOGFILE}) 2> >(tee -a ${LOGFILE} >/dev/null)
### All output to one file, STDERR to the screen
### Note you need both of these lines for this to work
#exec 3>&1
#exec > >(tee -a ${LOGFILE} >/dev/null) 2> >(tee -a ${LOGFILE} >&3)
### STDOUT to STATUSFILE, stderr to LOGFILE, nothing to the screen
#exec > ${STATUSFILE} 2>${LOGFILE}
### STDOUT to STATUSFILE, stderr to LOGFILE and all output to the screen
#exec > >(tee ${STATUSFILE}) 2> >(tee ${LOGFILE} >&2)
### STDOUT to STATUSFILE and screen, STDERR to LOGFILE
#exec > >(tee ${STATUSFILE}) 2>${LOGFILE}
### STDOUT to STATUSFILE, STDERR to LOGFILE and screen
#exec > ${STATUSFILE} 2> >(tee ${LOGFILE} >&2)
echo "This is a test"
ls -l sdgshgswogswghthb_this_file_will_not_exist_so_we_get_output_to_stderr_aronkjegralhfaff
ls -l ${0}
exec >
bir dosya tanımlayıcısının hedefini belirli bir hedefe taşımak anlamına gelir. Varsayılan 1'dir, bu nedenle exec > /dev/null
bu oturumda stdout çıktısını şu andan itibaren / dev / null değerine taşır. Bu oturum için geçerli dosya tanımlayıcıları yaparak görülebilir ls -l /dev/fd/
. Dene! Sonra exec 2>/tmp/stderr.log.
, sorun olduğunda ne olacağını görün Ayrıca, exec 3>&1
3 numaralı yeni bir dosya tanımlayıcı oluşturmak ve dosya tanımlayıcı 1 hedefine yönlendirmek anlamına gelir. Örnekte, hedef komut verildiğinde ekran oldu.
Stderr dosyasını bir dosyaya yeniden yönlendirmek için stdout'u ekrana görüntüleyin ve stdout'u bir dosyaya kaydedin:
./aaa.sh 2> ccc.out | tee ./bbb.out
DÜZENLEME : Stderr ve stdout'u ekrana görüntülemek ve her ikisini de bir dosyaya kaydetmek için bash'ın G / Ç yönlendirmesini kullanabilirsiniz :
#!/bin/bash
# Create a new file descriptor 4, pointed at the file
# which will receive stderr.
exec 4<>ccc.out
# Also print the contents of this file to screen.
tail -f ccc.out &
# Run the command; tee stdout as normal, and send stderr
# to our file descriptor 4.
./aaa.sh 2>&4 | tee bbb.out
# Clean up: Close file descriptor 4 and kill tail -f.
exec 4>&-
kill %1
Başka bir deyişle, stdout'u bir filtreye ( tee bbb.out
) ve stderr'ı başka bir filtreye ( ) bağlamak istiyorsunuz tee ccc.out
. Stdout dışında herhangi bir şeyi başka bir komuta dönüştürmenin standart bir yolu yoktur, ancak dosya tanımlayıcılarını hokkabazlayarak bu sorunu çözebilirsiniz.
{ { ./aaa.sh | tee bbb.out; } 2>&1 1>&3 | tee ccc.out; } 3>&1 1>&2
Ayrıca bkz. Standart hata akışı (stderr) nasıl grep? ve Ne zaman ek bir dosya tanımlayıcı kullanırsınız?
Bash (ve ksh ve zsh) 'de, ancak tire gibi diğer POSIX mermilerinde değil, işlem ikamesini kullanabilirsiniz :
./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out)
Bash'de, komutlar yine de yürütülse ./aaa.sh
bile , bu komutun biter bitmez geri döndüğüne dikkat edin tee
(ksh ve zsh, alt süreçleri bekler). Böyle bir şey yaparsanız bu bir sorun olabilir ./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out); process_logs bbb.out ccc.out
. Bu durumda, dosya tanımlayıcı hokkabazlık veya ksh / zsh kullanın.
sh
Süreç ikamesinin mevcut olmadığı cron işleri için yararlı olan en basit yaklaşım .
Bash kullanıyorsanız:
# Redirect standard out and standard error separately
% cmd >stdout-redirect 2>stderr-redirect
# Redirect standard error and out together
% cmd >stdout-redirect 2>&1
# Merge standard error with standard out and pipe
% cmd 2>&1 |cmd2
Kredi (başımın tepesinden cevap vermemek) buraya: http://www.cygwin.com/ml/cygwin/2003-06/msg00772.html
Benim durumumda, bir komut dosyası hem stdout hem de stderr'ı bir dosyaya yeniden yönlendirirken komut çalıştırıyordu:
cmd > log 2>&1
Bir hata olduğunda, hata mesajlarına dayalı bazı eylemler gerçekleştirecek şekilde güncellemem gerekiyordu. Tabii ki dup kaldırmak 2>&1
ve komut dosyasından stderr yakalamak, ama sonra hata mesajları referans için günlük dosyasına gitmez. @Lhunath'ın kabul edilen cevabının aynı şeyi yapması gerekiyorsa da, yönlendiriyor stdout
ve stderr
farklı dosyalara, istediğim şey değil, ancak tam olarak ihtiyacım olan çözümü bulmama yardımcı oldu:
(cmd 2> >(tee /dev/stderr)) > log
Yukarıdaki ile, günlük ikisinin bir kopyasına sahip olacak stdout
ve stderr
ben yakalayabilir stderr
hakkında endişe etmeden benim komut dosyasından stdout
.
Süreç ikamesinin mevcut olmadığı KornShell (ksh) için çalışacaktır,
# create a combined(stdin and stdout) collector
exec 3 <> combined.log
# stream stderr instead of stdout to tee, while draining all stdout to the collector
./aaa.sh 2>&1 1>&3 | tee -a stderr.log 1>&3
# cleanup collector
exec 3>&-
Burada gerçek hüner, bir dizisidir 2>&1 1>&3
bizim durumumuzda yönlendirir stderr
için stdout
ve yönlendirir stdout
tanımlayıcı 3
. Bu noktada stderr
ve stdout
henüz birleştirilmemiştir.
Aslında, stderr
(as stdin
) tee
oturum açtığı yere aktarılır stderr.log
ve tanımlayıcı 3'e yönlendirilir.
Ve tanımlayıcı 3
her zaman günlüğe kaydediyor combined.log
. Yani combined.log
hem içerir stdout
ve stderr
.
Zsh kullanıyorsanız , birden fazla yönlendirme kullanabilirsiniz, böylece ihtiyacınız bile olmaz tee
:
./cmd 1>&1 2>&2 1>out_file 2>err_file
Burada her bir akışı kendinize ve hedef dosyaya yönlendiriyorsunuz.
Tam örnek
% (echo "out"; echo "err">/dev/stderr) 1>&1 2>&2 1>/tmp/out_file 2>/tmp/err_file
out
err
% cat /tmp/out_file
out
% cat /tmp/err_file
err
Bunun MULTIOS
seçeneğin ayarlanmasını gerektirdiğini unutmayın (varsayılan değerdir).
MULTIOS
Birden çok yeniden yönlendirme denenirken örtük
tee
s veyacat
s gerçekleştirin (bkz. Yeniden Yönlendirme ).