Ben nasıl kullanılacağını bilmek teeçıkışını (yazmak için STDOUTbir) aaa.shiçin bbb.outhala Terminalde bunu görüntülenirken,:
./aaa.sh | tee bbb.out
Şimdi görüntülenirken, şimdi STDERRadlı bir dosyaya nasıl yazabilirim ccc.out?
Ben nasıl kullanılacağını bilmek teeçıkışını (yazmak için STDOUTbir) aaa.shiçin bbb.outhala Terminalde bunu görüntülenirken,:
./aaa.sh | tee bbb.out
Şimdi görüntülenirken, şimdi STDERRadlı bir dosyaya nasıl yazabilirim ccc.out?
Yanıtlar:
Terminalde hala STDERR ve STDOUT'u görmek istediğinizi varsayıyorum. Josh tailKelley'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 teedinlemenizi sağlar . Ardından, >STDOUT öğesinin commandilkini teedinlediği FIFO'ya yönlendirmek için (dosya yönlendirme) kullanır .
İkincisi için aynı şey:
2> >(tee -a stderr.log >&2)
teeSTDIN'den okunan ve onu içine alan bir işlem yapmak için süreç ikamesini tekrar kullanırız stderr.log. teegirişini tekrar STDOUT'a gönderir, ancak girişi teeSTDERR'ımız olduğu için STDOUT'u tekrar STDERR'ımıza yönlendirmek isteriz. Daha sonra commandSTDERR 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) bashyerine 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> errve/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 stderriç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 pipefailsonrası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/nullbu 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>&13 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.shbile , 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.
shSü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>&1ve 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 stdoutve stderrfarklı 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 stdoutve stderrben yakalayabilir stderrhakkı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>&3bizim durumumuzda yönlendirir stderriçin stdoutve yönlendirir stdouttanımlayıcı 3. Bu noktada stderrve stdouthenüz birleştirilmemiştir.
Aslında, stderr(as stdin) teeoturum açtığı yere aktarılır stderr.logve tanımlayıcı 3'e yönlendirilir.
Ve tanımlayıcı 3her zaman günlüğe kaydediyor combined.log. Yani combined.loghem içerir stdoutve 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 MULTIOSseçeneğin ayarlanmasını gerektirdiğini unutmayın (varsayılan değerdir).
MULTIOSBirden çok yeniden yönlendirme denenirken örtük
tees veyacats gerçekleştirin (bkz. Yeniden Yönlendirme ).