Stderr bir dosyaya yeniden yönlendirme

Arka planda çalışacak bir komut koymak için nohup kullanırken, içeriğin bir kısmı terminal'de görünür.

cp: error reading ‘/mnt/tt/file.txt’: Input/output errorcp: failed to extend ‘/mnt/tt/file.txt’: Input/output error

Bu içeriği bir dosyaya kaydetmek istiyorum.

Linux'ta (ve diğer işletim sistemlerinde) standart çıktı (stdout) ve standart hata (stderr) olmak üzere iki ana çıktı akışı vardır. Gösterdikleriniz gibi hata iletileri standart hataya yazdırılır. Klasik yeniden yönlendirme işleci (command > file) yalnızca standart çıktıyı yönlendirir, bu nedenle standart hata hala terminalde gösterilir. Stderr'yi de yönlendirmek için birkaç seçeneğiniz vardır:

  1. Stdout'u bir dosyaya ve stderr'yi başka bir dosyaya yönlendir:

    command > out 2>error
  2. Stdout'u bir dosyaya yeniden yönlendir (>out) ve sonra stderr'yi stdout'a yönlendirin (2>&1):

    command >out 2>&1
  3. Her ikisini de bir dosyaya yönlendirin (bu, tüm kabuklar tarafından desteklenmez, bash ve zsh örneğin, destekleyin, ancak sh ve ksh yapmayın):

    command &> out

Çeşitli denetim ve yeniden yönlendirme işleçleri hakkında daha fazla bilgi için bkz: burada.

Dikkat edilmesi gereken ilk şey, amacınıza ve kabuğunuza bağlı olarak birkaç yol olmasıdır, bu nedenle bu, birden fazla yönün hafifçe anlaşılmasını gerektirir. Ayrıca, aşağıdaki gibi belirli komutlar time ve strace çıktıyı varsayılan olarak stderr'ye yazın ve bu komuta özgü bir yeniden yönlendirme yöntemi sağlayabilir veya vermeyebilir

Yeniden yönlendirmenin ardındaki temel teori, kabuk tarafından oluşturulan bir işlemin (kabuk yerleşik değil, harici bir komut olduğu varsayılarak) oluşturulmasıdır fork() ve execve() syscalls ve bundan önce başka bir syscall olur dup2() daha önce gerekli yönlendirmeleri gerçekleştirir execve() olur. Bu anlamda yönlendirmeler üst kabuktan devralınır. Bu m&>n ve m>n.txt kabuğun nasıl gerçekleştirileceği hakkında bilgi verin open() ve dup2() syscall (ayrıca bkz. Girdi yeniden yönlendirmesi nasıl çalışır?, Yönlendirme ve kanal arasındaki fark nedir, ve Çıktı yönlendirmesinde & tam olarak ne anlama geliyor )

Kabuk yönlendirmeleri

En tipik, via 2> içinde Bourne benzeri kabuklar, mesela dash (sembolik olarak bağlı olan /bin/sh) ve bash birincisi varsayılan ve POSIX uyumlu kabuk, diğeri ise çoğu kullanıcının etkileşimli oturum için kullandığı kabuktur. Sözdizimi ve özelliklerde farklılık gösterirler, ancak neyse ki bizim için hata akışı yeniden yönlendirmesi aynı şekilde çalışır (hariç &> standart olmayan). Csh ve türevleri durumunda, stderr yönlendirmesi orada pek işe yaramıyor.

Geri dönelim 2> parça. Dikkat edilmesi gereken iki önemli şey: > bir dosyayı açtığımız yönlendirme operatörü anlamına gelir ve 2 tamsayı, stderr dosya tanımlayıcısı anlamına gelir; aslında bu, kabuk dili için POSIX standardının yönlendirmeyi tam olarak nasıl tanımladığıdır bölüm 2.7:

[n]redir-op word

Basit için > yönlendirme, 1 tamsayı için ima edilir stdout, yani. echo Hello World > /dev/null sadece aynı echo Hello World 1>/dev/null. Tamsayı veya yeniden yönlendirme işlecinin alıntılanamayacağını unutmayın, aksi halde shell bunları tanımıyor ve bunun yerine değişmez metin dizesi olarak ele alıyor. Boşluklara gelince, integer'ın yeniden yönlendirme operatörünün hemen yanında olması önemlidir, ancak dosya yeniden yönlendirme operatörünün yanında olabilir veya olmayabilir, yani. command 2>/dev/null ve command 2> /dev/null gayet iyi çalışacaktır.

Kabuktaki tipik komut için biraz basitleştirilmiş sözdizimi şöyle olacaktır

 command [arg1] [arg2]  2> /dev/null

Buradaki hile, yönlendirmenin herhangi bir yerde görünebilmesidir. Bu ikisi de 2> command [arg1] ve command 2> [arg1] geçerlidirler. Bunun için dikkat edin bash kabuk, orada var &> hem stdout hem de stderr akışlarını aynı anda yeniden yönlendirmenin yolu, ancak yine de - bash'a özgüdür ve komut dosyalarının taşınabilirliği için çabalıyorsanız, çalışmayabilir. Ayrıca bakınız Ubuntu Wiki ve >>&Amp; ve 2 &1 arasındaki fark nedir.

Not: Bu > yönlendirme işleci buduyor bir dosya ve dosya varsa üzerine yazar. Bu 2>> eklemek için kullanılabilir stderr dosyalamak.

Eğer fark ederseniz, > tek bir komut içindir. Komut dosyaları için, tüm komut dosyasının stderr akışını dışarıdan olduğu gibi yönlendirebiliriz myscript.sh 2> /dev/null ya da faydalanabiliriz exec yerleşik. Yerleşik exec, etkileşimli olarak veya komut dosyası aracılığıyla, tüm kabuk oturumu için akışı yeniden bağlama gücüne sahiptir. Aşağı yukarı

#!/bin/shexec 2> ./my_log_file.txtstat /etc/non_existing_file

Bu örnekte, günlük dosyası şunları göstermelidir stat: cannot stat '/etc/non_existing_file': No such file or directory.

Başka bir yol da işlevlerdir. Olarak külkedisi cevabında belirtildiği gibi, zaten eklenmiş yönlendirme ile işlev bildirimi yazabiliriz, yani

some_function(){    command1    command2} 2> my_log_file.txt

Yalnızca stderr'ye yazma komutları

Aşağıdaki gibi komutlar time ve strace çıktılarını varsayılan olarak stderr'ye yazın. Durumunda time komut, tek geçerli alternatif, tüm komutun çıktısını yeniden yönlendirmektir, yani

time echo foo 2>&1 > file.txt

alternatif olarak, çıktıyı ayırmak istiyorsanız senkronize liste veya alt kabuk yeniden yönlendirilebilir (gösterildiği gibi ilgili gönderi ):

{ time sleep 1 2> sleep.stderr ; } 2> time.txt

Diğer komutlar, örneğin strace veya dialog stderr'yi yönlendirmek için araçlar sağlayın. strace var -o <filename.txt> çıktı yazılması gereken dosya adını belirtmeyi sağlayan seçenek. Her alt işlem için bir metin dosyası yazmak için bir seçenek de vardır strace görür. Bu dialog komut, metin kullanıcı arayüzünü stdout'a yazar, ancak çıktıyı stderr'ye yazar, böylece çıktısını değişkene kaydet ( çünkü var=$(...) ve boru hatları sadece stderr alır) dosya tanımlayıcılarını değiştirmemiz gerekir

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);

ancak ek olarak, var --output-fd bayrağı da kullanabiliriz. Adlandırılmış yöneltmeler yöntemi de vardır. Bu konuyla ilgili bağlantılı yazıyı okumanızı tavsiye ederim. dialog neler olup bittiğinin ayrıntılı açıklaması için komuta edin.

@terdon Bu daha spesifik bir sorudur ve daha spesifik soru için google aramasında haklı olarak ortaya çıkar, ki bu iyi bir şeydir.

@nroose evet ve görünmeye devam edecek, bu değişmeyecek. Ancak yeni cevaplar daha genel soruya gitmelidir.