Stderr ve stdout'u Bash'e yönlendir


678

Bir işlemin stdout ve stderr'ını tek bir dosyaya yeniden yönlendirmek istiyorum. Bunu Bash'de nasıl yapabilirim?


2
Bunun şaşırtıcı derecede faydalı bir soru olduğunu söylemek isterim. Birçok insan bunu nasıl yapacağını bilmiyor, çünkü çok sık yapmak zorunda değiller ve bu Bash'in en iyi belgelenmiş davranışı değildir.
Robert Wm Ruedisueli

2
Bazen çıktıyı görmek (her zamanki gibi) VE bir dosyaya yönlendirmek yararlı olabilir. Aşağıdaki Marko'nun cevabına bakınız. (Bunu burada söylüyorum çünkü bir sorunu çözmek için yeterliyse ilk kabul edilen cevaba bakmak kolaydır, ancak diğer cevaplar genellikle yararlı bilgiler sağlar.)
jvriesem

Yanıtlar:


762

Buraya bir bak . Olmalı:

yourcommand &>filename

(her ikisini de stdoutve stderrdosya adına yönlendirir ).


29
Bu sözdizimi Bash Hackers Wiki'ye göre kullanımdan kaldırıldı . Bu mu?
Salman von Abbas

20
Wiki.bash-hackers.org/scripting/obsolete'ye göre, POSIX'in bir parçası olmadığı anlamında eski gibi görünüyor, ancak bash man sayfası, yakın gelecekte bash'tan kaldırıldığından bahsetmiyor. Man sayfasında aksi takdirde eşdeğer olan '&>' over '> &' için bir tercih belirtilir.
chepner

13
POSIX'te olmadığı için &> kullanmamalıyız ve "çizgi" gibi yaygın mermiler bunu desteklemiyor.
Sam Watkins

27
Ekstra bir ipucu: Bunu bir komut dosyasında kullanırsanız, bunun #!/bin/bashyerine #!/bin/shbash gerektirdiğinden, bunun yerine ile başladığından emin olun .
Tor Klingberg

8
Veya üzerine yazmak yerine & >> ekleyin.
Alexander Gonchiy

449
do_something 2>&1 | tee -a some_file

Bu stdout ve Stdout'a stderr'yi yönlendirmek için gidiyor some_file ve stdout'a yazdırmak.


16
AIX (ksh) üzerinde çözümünüz çalışır. Kabul edilen cevap do_something &>filenamevermez. +1.
Withheld

11
@Daniel, ama bu soru özellikle bash hakkında
John La Rooy

3
Elde Ambiguous output redirect.neden bir fikrin?
Alexandre Holden Daly

1
Hata mesajlarını kalın kırmızı renkte basan bir ruby ​​komut dosyası (ki hiçbir şekilde değiştirmek istemiyorum) var. Bu ruby ​​betiği daha sonra bash betiğimden (değiştirebileceğim) çağrılır. Yukarıdakileri kullandığımda, hata mesajlarını biçimlendirme eksi olarak düz metin olarak yazdırır. Ekran biçimlendirmesini korumanın ve çıktıyı (hem stdout hem de stderr) bir dosyada almanın herhangi bir yolu var mı?
atlantis

8
Bunun (varsayılan olarak) $?artık çıkış durumuyla do_somethingdeğil, çıkış durumuyla ilgili yan etkisi olduğunu unutmayın tee.
Flimm

255

Sen yönlendirebilirsiniz stderr'yi için stdout ve stdout bir dosyaya:

some_command >file.log 2>&1 

Bkz. Http://tldp.org/LDP/abs/html/io-redirection.html

Bu biçim, yalnızca bash ile çalışan en popüler &> biçiminden daha çok tercih edilir. Bourne kabuğunda, komutu arka planda çalıştırmak olarak yorumlanabilir. Ayrıca biçim daha okunabilir 2 (STDERR) 1'e (STDOUT) yönlendirilir.

DÜZENLEME: yorumlarda belirtildiği gibi sırayı değiştirdi


47
Bu, stderr'ı stdout'un gittiği dosyaya değil, orijinal stdout'a yönlendirir. '> File.log' ifadesinin arkasına '2> & 1' koyun ve işe yarar.

1
Bu yaklaşımın some_command &> file.log'a göre avantajı nedir?
ubermonkey

6
Bir dosyaya eklemek istiyorsanız, bunu şu şekilde yapmanız gerekir: echo "foo" 2> & 1 1 >> bar.txt AFAIK,
SlappyTheFish

9
Ah, üzgünüm, yankı "foo" 1 >> bar.txt 2> & 1
SlappyTheFish

11
2> 1'in stderr'ı stdout'a yönlendirdiği yorumu yanlış olduğunu düşünüyorum; Ben stderr şu anda gidiyor aynı yere stderr gönderdiğini söylemek daha doğru olduğuna inanıyorum. Bu nedenle , ilk yönlendirmeden sonra 2> & 1 koyun.
jdg

201
# Close STDOUT file descriptor
exec 1<&-
# Close STDERR FD
exec 2<&-

# Open STDOUT as $LOG_FILE file for read and write.
exec 1<>$LOG_FILE

# Redirect STDERR to STDOUT
exec 2>&1

echo "This line will appear in $LOG_FILE, not 'on screen'"

Şimdi, basit yankı $ LOG_FILE dosyasına yazacak. Arka plan programı için kullanışlıdır.

Orijinal yazının yazarına,

Neyi başarmanız gerektiğine bağlıdır. Betiğinizden aradığınız bir komutun içine / dışına yönlendirmeniz gerekiyorsa, yanıtlar zaten verilmiştir. Benimki, söz konusu kod snippet'inden sonra tüm komutları / yerleşikleri (çatalları içerir) etkileyen geçerli komut dosyası içinde yeniden yönlendirmeyle ilgilidir .


Bir başka harika çözüm, hem bir std-err / out AND'e hem de bir günlükçüye veya günlük dosyasına yönlendirme ile ilgilidir. Bu işlevsellik, aynı anda birkaç dosya tanımlayıcısını (dosyalar, soketler, borular vb.) Yazabilen / ekleyebilen 'tee' komutu ile sağlanır: tee FILE1 FILE2 ...> (cmd1)> (cmd2) ...

exec 3>&1 4>&2 1> >(tee >(logger -i -t 'my_script_tag') >&3) 2> >(tee >(logger -i -t 'my_script_tag') >&4)
trap 'cleanup' INT QUIT TERM EXIT


get_pids_of_ppid() {
    local ppid="$1"

    RETVAL=''
    local pids=`ps x -o pid,ppid | awk "\\$2 == \\"$ppid\\" { print \\$1 }"`
    RETVAL="$pids"
}


# Needed to kill processes running in background
cleanup() {
    local current_pid element
    local pids=( "$$" )

    running_pids=("${pids[@]}")

    while :; do
        current_pid="${running_pids[0]}"
        [ -z "$current_pid" ] && break

        running_pids=("${running_pids[@]:1}")
        get_pids_of_ppid $current_pid
        local new_pids="$RETVAL"
        [ -z "$new_pids" ] && continue

        for element in $new_pids; do
            running_pids+=("$element")
            pids=("$element" "${pids[@]}")
        done
    done

    kill ${pids[@]} 2>/dev/null
}

Yani, en başından. Diyelim ki / dev / stdout (FD # 1) ve / dev / stderr (FD # 2) 'ye bağlı terminalimiz var. Uygulamada, bir boru, soket veya başka bir şey olabilir.

  • FD # 3 ve # 4 oluşturun ve sırasıyla # 1 ve # 2 ile aynı "konumu" işaret edin. FD # 1'i değiştirmek bundan sonra FD # 3'ü etkilemez. Şimdi, FD # 3 ve # 4 sırasıyla STDOUT ve STDERR'yi gösteriyor. Bunlar gerçek terminal STDOUT ve STDERR olarak kullanılacaktır .
  • 1>> (...) STDOUT'u parenlerdeki komuta yönlendirir
  • parens (alt kabuk), exec'in STDOUT (boru) öğesinden 'tee' okumasını yürütür ve başka bir boru aracılığıyla parens içindeki alt kabuğa 'logger' komutuna yönlendirir. Aynı zamanda FD # 3'e (terminal) aynı girişi kopyalar
  • ikinci bölüm, çok benzer, STDERR ve FD # 2 ve # 4 için aynı hileyi yapmakla ilgilidir.

Yukarıdaki satıra ve ayrıca buna sahip bir komut dosyası çalıştırmanın sonucu:

echo "Will end up in STDOUT(terminal) and /var/log/messages"

...Şöyleki:

$ ./my_script
Will end up in STDOUT(terminal) and /var/log/messages

$ tail -n1 /var/log/messages
Sep 23 15:54:03 wks056 my_script_tag[11644]: Will end up in STDOUT(terminal) and /var/log/messages

Daha net resim görmek istiyorsanız betiğe şu 2 satırı ekleyin:

ls -l /proc/self/fd/
ps xf

1
sadece bir istisna. yazdığınız ilk örnekte: exec 1 <> $ LOG_FILE. özgün günlük dosyası her zaman yazılır. gerçek loggin için daha iyi bir yol: exec 1 >> $ LOG_FILE günlük eklenir neden olur.
Znik

4
Niyetlere bağlı olmasına rağmen bu doğrudur. Benim yaklaşımım her zaman benzersiz ve zaman damgalı bir günlük dosyası oluşturmaktır. Diğeri ise eklemektir. Her iki yol da 'logrotateable'. Daha az ayrıştırma gerektiren ayrı dosyaları tercih ederim ama dediğim gibi, teknenizi yüzer hale getiren ne olursa olsun :)
quizac

1
İkinci çözümünüz bilgilendiricidir, ancak tüm temizleme kodunda ne var? Alakalı görünmüyor ve eğer öyleyse, sadece iyi bir örnek karıştırıyor. Ayrıca, FDs 1 ve 2'nin kaydediciye yönlendirilmemesi için biraz yeniden çalıştığını görmek istiyorum, ancak 3 ve 4, bu komut dosyasını çağıran her şeyin ortak varsayım altında 1 ve 2'yi daha fazla manipüle edebileceği şekilde == 1 ve stderr == 2, ancak kısa denemem bunun daha karmaşık olduğunu gösteriyor.
JFlo

1
Temizleme kodu ile daha iyi seviyorum. Çekirdek örnekten biraz dikkat dağıtıcı olabilir, ancak onu kaldırmak, örneği tamamlayamaz. Net, hata işleme olmadan zaten örneklerle doludur veya en azından kullanım için güvenli olması için yaklaşık yüz kod satırına ihtiyaç duyduğunu gösteren kolay bir not.
Zoltan K.

1
Temizlik kodunu detaylandırmak istedim. Bu, ergo'yu HANG-UP sinyaline bağışık hale getiren betik bir parçasıdır. 'tee' ve 'logger' aynı PPID tarafından üretilen süreçlerdir ve HUP tuzağını ana bash betiğinden miras alırlar. Böylece, ana süreç öldükten sonra init tarafından miras alınırlar [1]. Zombiler olmayacaklar (defunc). Temizleme kodu, ana komut dosyası ölürse tüm arka plan görevlerinin öldürülmesini sağlar. Ayrıca, arka planda oluşturulmuş ve çalışıyor olabilecek diğer tüm işlemler için de geçerlidir.
quizac

41
bash your_script.sh 1>file.log 2>&1

1>file.logkabuğa dosyaya STDOUT göndermesini söyler file.logve 2>&1STDERR'u (dosya tanıtıcı 2) STDOUT'a (dosya tanıtıcı 1) yönlendirmesini söyler.

Not: liw.fi'nin işaret ettiği gibi sipariş önemlidir, 2>&1 1>file.logçalışmaz.


21

Merakla, bu işe yarıyor:

yourcommand &> filename

Ancak bu bir sözdizimi hatası verir:

yourcommand &>> filename
syntax error near unexpected token `>'

Kullanmanız gerekenler:

yourcommand 1>> filename 2>&1

10
&>>BASH 4 üzerinde çalışıyor gibi görünüyor:$ echo $BASH_VERSION 4.1.5(1)-release $ (echo to stdout; echo to stderr > /dev/stderr) &>> /dev/null
user272735

15

Kısa cevap: Command >filename 2>&1veyaCommand &>filename


Açıklama:

"Stdout" sözcüğünü stdout'a ve "stderror" kelimesini stderror'a yazdıran aşağıdaki kodu düşünün.

$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror

'&' Operatörünün bash'a 2'nin bir dosya adı değil (stderr'yi gösteren) bir dosya tanıtıcısı olduğunu söylediğini unutmayın. '&' stdoutİşaretini dışarıda bırakırsak, bu komut stdout'a yazdırır ve "2" adlı bir dosya oluşturur ve stderrororaya yazar.

Yukarıdaki kodu deneyerek, yeniden yönlendirme operatörlerinin tam olarak nasıl çalıştığını kendiniz görebilirsiniz. Örneğin, iki tanımlayıcıdan hangisinin aşağıdaki iki kod satırına 1,2yönlendirildiğini değiştirerek /dev/nullstdout'tan her şeyi ve stderror'dan her şeyi siler (kalanları yazdırmak).

$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout

Şimdi, aşağıdaki kodun neden çıktı üretmediğini açıklayabiliriz:

(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1

Bunu gerçekten anlamak için, bu web sayfasını dosya tanımlayıcı tablolarında okumanızı şiddetle tavsiye ederim . Bu okumayı yaptığınızı varsayarsak, devam edebiliriz. Bash'in soldan sağa işlem yaptığını unutmayın; böylece Bash >/dev/nullönce (aynı olanı) görür 1>/dev/nullve dosya tanımlayıcı 1'i stdout yerine / dev / null olarak gösterecek şekilde ayarlar. Bunu yaptıktan sonra Bash sağa doğru hareket eder ve görür 2>&1. Bu, dosya tanıtıcısı 2'yi dosya tanıtıcısı 1 ile aynı dosyayı gösterecek şekilde ayarlar (dosya tanıtıcısı 1'in kendisini değil !!!!) işaretçilerdeki bu kaynağa bakındaha fazla bilgi için)) . Dosya tanımlayıcı 1 / dev / null değerini ve dosya tanımlayıcı 2, dosya tanımlayıcı 1 ile aynı dosyayı gösterdiğinden, dosya tanımlayıcı 2 artık / dev / null öğesini de gösterir. Bu nedenle, her iki dosya tanımlayıcısı da / dev / null değerini gösterir ve bu nedenle çıktı alınmaz.


Konsepti gerçekten anlayıp anlamadığınızı test etmek için, yeniden yönlendirme sırasını değiştirdiğimizde çıktıyı tahmin etmeye çalışın:

(echo "stdout"; echo "stderror" >&2)  2>&1 >/dev/null

Std. Hata

Buradaki mantık, soldan sağa değerlendirildiğinde Bash 2> & 1'i görür ve böylece dosya tanımlayıcı 2'yi dosya tanımlayıcı 1 ile aynı yere, yani stdout'a işaret edecek şekilde ayarlar. Daha sonra dosya tanımlayıcı 1'i (> / dev / null = 1> / dev / null)> / dev / null'a işaret edecek şekilde ayarlar, böylece genellikle standart çıkışa gönderilecek her şeyi siler. Böylece geriye kalan tek şey, alt kabukta (parantez içindeki kod) - yani "stderror" daki stdout'a gönderilmediği idi. Burada dikkat edilmesi gereken ilginç bir nokta, 1'in stdout'a bir işaretçi olmasına rağmen, 2'den 1'e doğru yönlendiricinin 2>&12 -> 1 -> stdout işaretçisi zincirini oluşturmamasıdır. 1 değerini / dev / null değerine yönlendirmenin bir sonucu olarak, kod2>&1 >/dev/null işaretçi zincirine 2 -> 1 -> / dev / null verir ve böylece kod, yukarıda gördüğümüzün aksine hiçbir şey üretmez.


Son olarak, bunu yapmanın daha basit bir yolu olduğunu unutmayın:

Burada 3.6.4 bölümünden , &>hem stdout hem de stderr'i yönlendirmek için operatörü kullanabileceğimizi görüyoruz . Bu nedenle, herhangi bir komutun hem stderr hem de stdout çıktısını (çıktıyı \dev\nullsiler) yeniden yönlendirmek için basitçe $ command &> /dev/null veya örneğim durumunda yazıyoruz:

$ (echo "stdout"; echo "stderror" >&2) &>/dev/null

Temel çıkarımlar:

  • Dosya tanımlayıcıları işaretçiler gibi davranır (dosya tanımlayıcıları dosya işaretçileriyle aynı olmasa da)
  • "A" dosya tanımlayıcısını "f" dosyasını işaret eden bir dosya tanımlayıcısına "b" yeniden yönlendirmek, "a" dosya tanımlayıcısının, dosya tanımlayıcı b - dosyası "f" ile aynı yeri göstermesine neden olur. A -> b -> f işaretçiler zinciri oluşturmaz
  • Çünkü yukarıda, sipariş konularda, 2>&1 >/dev/nullolduğu! = >/dev/null 2>&1. Biri çıktı üretir, diğeri vermez!

Son olarak şu harika kaynaklara bir göz atın:

Yeniden Yönlendirme üzerinde Bash Belgeler , Dosya Tanıtıcı Tablolar Bir Açıklama , İşaretçiler giriş


Dosya tanımlayıcıları (0, 1, 2) bir tablonun yalnızca ofsetleridir. 2> & 1 kullanıldığında, etki FD [2] = dup (1) yuvasıdır, böylece FD [1] 'in FD [2]' yi işaret ettiği her yerde şimdi işaret eder. FD [1] 'i / dev / null' u gösterecek şekilde değiştirdiğinizde, FD [1] değiştirilir ancak FD [2] yuvasını değiştirmez (stdout'a işaret eder). Dosya tanımlayıcısını çoğaltmak için kullanılan sistem çağrısı olduğundan dup () terimini kullanıyorum.
PatS

11
LOG_FACILITY="local7.notice"
LOG_TOPIC="my-prog-name"
LOG_TOPIC_OUT="$LOG_TOPIC-out[$$]"
LOG_TOPIC_ERR="$LOG_TOPIC-err[$$]"

exec 3>&1 > >(tee -a /dev/fd/3 | logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_OUT" )
exec 2> >(logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_ERR" )

İlgili: syslog'a stdOut & stderr yazmak.

Neredeyse işe yarıyor, ama xinted'dan değil;


"/ Dev / fd / 3 İzin reddedildi" nedeniyle çalışmadığını tahmin ediyorum. > & 3 değerine geçmek yardımcı olabilir.
quizac

6

Ben stdout artı stderr çıktı bir günlük dosyası ve hala konsolda stderr yazılı bir çözüm istedim. Bu yüzden tee yoluyla stderr çıktısını çoğaltmam gerekiyordu.

Bulduğum çözüm bu:

command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
  • İlk takas stderr ve stdout
  • sonra stdout'u günlük dosyasına ekleyin
  • boru stderr tee ve günlük dosyasına da eklemek

BTW, bu benim için işe yaramadı (günlük dosyası boş). | tee'nin bir etkisi yoktur. Bunun yerine stackoverflow.com/questions/692000/…
Yaroslav Bulatov

4

Durum için, "boru tesisatı" gerektiğinde şunları kullanabilirsiniz:

| &

Örneğin:

echo -ne "15\n100\n"|sort -c |& tee >sort_result.txt

veya

TIMEFORMAT=%R;for i in `seq 1 20` ; do time kubectl get pods |grep node >>js.log  ; done |& sort -h

Bu bash tabanlı çözümler STDOUT ve STDERR'ı ayrı ayrı borulandırabilir ("sort -c" nin STDERR'sinden veya STDERR'den "sort -h" ye).


1

"En kolay" yolu (bash4 için): ls * 2>&- 1>&-.


1

Aşağıdaki işlevler, stdout / stderr ve bir logfile arasındaki çıkışları değiştirme işlemini otomatikleştirmek için kullanılabilir.

#!/bin/bash

    #set -x

    # global vars
    OUTPUTS_REDIRECTED="false"
    LOGFILE=/dev/stdout

    # "private" function used by redirect_outputs_to_logfile()
    function save_standard_outputs {
        if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
            exit 1;
        fi
        exec 3>&1
        exec 4>&2

        trap restore_standard_outputs EXIT
    }

    # Params: $1 => logfile to write to
    function redirect_outputs_to_logfile {
        if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
            exit 1;
        fi
        LOGFILE=$1
        if [ -z "$LOGFILE" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"

        fi
        if [ ! -f $LOGFILE ]; then
            touch $LOGFILE
        fi
        if [ ! -f $LOGFILE ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
            exit 1
        fi

        save_standard_outputs

        exec 1>>${LOGFILE%.log}.log
        exec 2>&1
        OUTPUTS_REDIRECTED="true"
    }

    # "private" function used by save_standard_outputs() 
    function restore_standard_outputs {
        if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot restore standard outputs because they have NOT been redirected"
            exit 1;
        fi
        exec 1>&-   #closes FD 1 (logfile)
        exec 2>&-   #closes FD 2 (logfile)
        exec 2>&4   #restore stderr
        exec 1>&3   #restore stdout

        OUTPUTS_REDIRECTED="false"
    }

Betik içindeki kullanım örneği:

echo "this goes to stdout"
redirect_outputs_to_logfile /tmp/one.log
echo "this goes to logfile"
restore_standard_outputs 
echo "this goes to stdout"

fonksiyonlarınızı kullandığımda ve standart çıktıları geri yüklemeye çalıştığımda yankı alıyorum: yazma hatası: Yönlendirme kusursuz bir şekilde çalışıyor ... geri yükleme öyle görünmüyor
thom schumacher

Senaryonuz üzerinde çalışmak için bu satırları yorum vardı ve sırayı değiştirdim: #exec 1> & - #closes FD 1 (logfile) #exec 2> & - #closes FD 2 (logfile); exec 1> & 3 #restore stdout exec 2> & 4 #restore stderr
thom schumacher

Bunu duyduğuma üzüldüm. CentOS 7, bash 4.2.46'da çalışırken herhangi bir hata almıyorum. Bu komutları aldığım referansa açıklama ekledim. Bu: Ref: logan.tw/posts/2016/02/20/open-and-close-files-in-bash
Fernando Fabreti

Bu komutları muhtemelen AIX üzerinde çalıştırıyorum. Yaptığım düzeltme için bir yazı ekledim.
thom schumacher

1

@ Fernando-fabreti

Yaptıklarınıza ek olarak işlevleri biraz değiştirdim ve & - kapanışını kaldırdım ve benim için çalıştı.

    function saveStandardOutputs {
      if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
        exec 3>&1
        exec 4>&2
        trap restoreStandardOutputs EXIT
      else
          echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
          exit 1;
      fi
  }

  # Params: $1 => logfile to write to
  function redirectOutputsToLogfile {
      if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
        LOGFILE=$1
        if [ -z "$LOGFILE" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"
        fi
        if [ ! -f $LOGFILE ]; then
            touch $LOGFILE
        fi
        if [ ! -f $LOGFILE ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
            exit 1
        fi
        saveStandardOutputs
        exec 1>>${LOGFILE}
        exec 2>&1
        OUTPUTS_REDIRECTED="true"
      else
        echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
          exit 1;
      fi
  }
  function restoreStandardOutputs {
      if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
      exec 1>&3   #restore stdout
      exec 2>&4   #restore stderr
      OUTPUTS_REDIRECTED="false"
     fi
  }
  LOGFILE_NAME="tmp/one.log"
  OUTPUTS_REDIRECTED="false"

  echo "this goes to stdout"
  redirectOutputsToLogfile $LOGFILE_NAME
  echo "this goes to logfile"
  echo "${LOGFILE_NAME}"
  restoreStandardOutputs 
  echo "After restore this goes to stdout"

1

Böyle şeyleri kullanmayı düşündüğünüz durumlarda, exec 2>&1mümkünse aşağıdaki gibi bash işlevlerini kullanarak kodu yeniden yazmak daha kolay okunur:

function myfunc(){
  [...]
}

myfunc &>mylog.log

0

Tcsh için aşağıdaki komutu kullanmalıyım:

command >& file

Kullanılırsa command &> file, "Geçersiz boş komut" hatası verir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.