Dizindeki find
tüm pdf dosyalarını görmek için kullandığımda /home
görüyorum access denied
. Onları ortadan kaldırmak için denedim:
find /home -iname "*.pdf" | grep -v "access denied"
Ancak sonuç aynıdır. Bu çizgilerden nasıl kurtulabilirim?
Dizindeki find
tüm pdf dosyalarını görmek için kullandığımda /home
görüyorum access denied
. Onları ortadan kaldırmak için denedim:
find /home -iname "*.pdf" | grep -v "access denied"
Ancak sonuç aynıdır. Bu çizgilerden nasıl kurtulabilirim?
Yanıtlar:
access denied
Çıktınız hatalar olduğu ve çalışılan STDOUT yerine STDERR'a gönderildiği için denediğiniz şey işe yaramadı grep
.
Yalnızca STDERR'ı yeniden yönlendirerek bu hataları görmekten kaçınabilirsiniz
find /home -iname "*.pdf" 2>/dev/null
Ya da David Foerster'ın söylediği gibi STDERR'ı daha özlü bir şekilde kapatabiliriz
find /home -iname "*.pdf" 2>&-
Ancak, aslında diğer kullanıcıların yerine sadece evinizi aramak istediğinizden şüpheleniyorum, belki de gerçekten
find ~ -iname "*.pdf"
Bu hata verirse, yerel yapılandırmanızda araştırmanız gereken bazı yanlış sahiplikler olabilir.
sudo chown $USER: ~/.gvfs ~/.dbus
2>&-
. GNU find, işlevsiz bir dosya tanımlayıcısına hata mesajları yazmaya çalışırsa kendisini sonlandırmaz. Sahiplik sorunları, sahip olunmayan sudo chown -R $USER: ...
dosyalar içinde daha fazla dosya olması durumunda daha etkili olacaktır $USER
.
Reddedilen erişim muhtemelen stderr
yerine yazdırılıyor stdout
.
Bunu dene:
find /home -iname "*.pdf" 2>&1 | grep -v "access denied"
2>&1
Çıktıyı yönlendirir stderr
için stdout
böylece grep -v
işini yapabilir. (Varsayılan olarak, |
yalnızca borular stdout
değil stderr
.)
2>&1
... Ben bash uzmanı değilim, bu yüzden yanlışsa lütfen bunu söyleyin :)
bash
Ubuntu'da POSIX modu hariç . Bence en iyi çözüm - kötü amaçlı olarak adlandırılmış bir dosya access denied
hala görünecektir.
Muhtemelen "İzin reddedildi" - find
"erişim reddedildi" yerine, dosya izinleri nedeniyle bir şeye erişemediğinizde Ubuntu'da size gösterilen şeydir.
Bunu doğru şekilde yapan tamamen genel bir komut (ve bir bonus olarak, hata mesajı aynı olduğu sürece diğer * nix'lere taşınabilir ):
(find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
(Genellikle bazı argümanları iletmek find
istersiniz. Bunlar ilk yönlendirmeden önce gelir 3>&1
.)
Bununla birlikte, genellikle daha basit bir şey kullanabilirsiniz. Örneğin, muhtemelen işlem ikamesi kullanabilirsiniz . Detaylar takip eder.
İki tipik yaklaşım stderr'i atmak ( Zanna'nın cevabında olduğu gibi ) veya stderr'ı stdout'a ve filtreleme stdoutuna ( Android Dev'in cevabında olduğu gibi ) yönlendirmektir. Yazması kolay olmaları ve genellikle makul seçimler olma avantajına sahip olmalarına rağmen, bu yaklaşımlar ideal değildir.
Stderr gönderilen her şeyi iptal edilmesi için yönlendirerek olarak -bunlar boş cihazla birlikte 2>/dev/null
veya onu kapatarak 2>&-
"İzin verilmedi" dışında hataları eksik riskini -çalıştırır.
"İzin reddedildi" muhtemelen çalışırken en sık karşılaşılan hatadır find
, ancak olası tek hatadan uzaktır ve başka bir hata oluşursa, bunu bilmek isteyebilirsiniz. Özellikle, find
bir başlangıç noktası yoksa "Böyle bir dosya veya dizin yok" bildirir. Birden fazla başlangıç noktasıyla, find
yine de bazı yararlı sonuçlar döndürebilir ve çalışıyor gibi görünebilir. Örneğin, eğer a
ve c
mevcut ama b
does not, find a b c -name x
içinde baskılar sonucu a
, sonra "Hayır böyle bir dosya veya dizini" b
in ardından sonuçların, c
.
Stdout ve stderr'ı stdout ile birleştirmek ve onugrep
filtrelemek için veya başka bir komutla borulandırmak - 2>&1 | grep ...
veya |& grep ...
olduğu gibi - adı filtrelenen iletiyi içeren bir dosyayı yanlışlıkla filtreleme riskini ortadan kaldırır.
Örneğin, "İzin reddedildi" içeren satırları filtrelerseniz, "İzin reddedildi iletileri.txt" gibi dosya adlarını gösteren arama sonuçlarını da bırakırsınız. Bu, muhtemelen bir tesadüfen olur, ancak bir dosyanın aramalarınızı engellemek için özel hazırlanmış bir ad vermesi de mümkündür.
Birleştirilen akışları filtre başka bir sorun, sahip olamaz daha seçici bir filtre hafifletilebilir (örneğin olduğu gibi grep -vx 'find: .*: Permission denied'
, borunun sağ tarafta). Hiçbir eylem belirtmediğinizde örtük find
olan -print
eylem de dahil olmak üzere bazı eylemler, stdout'un bir uçbirim olup olmadığına bağlı olarak dosya adlarının nasıl verileceğini belirler .
?
yerine yazdırılır.grep
) Aktarılması, find
artık bir terminal görmemesine neden olur . (Daha doğrusu, stdout'unun bir terminal olmamasına neden olur.) Sonra garip karakterler tam anlamıyla çıkar. Ancak, borunun sağ tarafındaki tüm komutlar yaparsa (a) "İzin reddedildi" mesajlarına benzeyen satırları kaldırın ve (b) geriye kalanları yazdırın, o zaman hala find
terminalin bir tür maskaralığına maruz kalırsınız algılama amaçlıdır.man find
Dosya adlarını basan eylemlerin her birinin davranışı da dahil olmak üzere daha fazla bilgi için , UNUSUAL FILENAMES bölümüne bakın . ( "Diğer kullanıcıların kontrolü altındadır verilerin baskıda bulmak sonucu eylemleri ... Birçok" ) bölümleri Ayrıca bkz 3.3.2.1 , 3.3.2.2 ve 3.3.2.3 arasında GNU Findutils referans kılavuzuna .Alışılmadık dosya adları ilgilidir yukarıdaki tartışma GNU bulmak olan find
Ubuntu dahil GNU / Linux sistemlerinde uygulanması.
Ne gerçekten burada istediğiniz bırakmaktır stdout'u Boru ederken bozulmamış stderr için grep
. Ne yazık ki bunun için basit bir sözdizimi yoktur. |
borular stdout ve bazı kabuklar (dahil bash
) |&
her iki akışı da boruya bağlar - ya da stderr'ı önce 2>&1 |
aynı etkiye sahip olan stdout'a yönlendirebilirsiniz . Ancak yaygın olarak kullanılan mermiler sadece boru stderrine bir sözdizimi sağlamaz.
Bunu hala yapabilirsiniz. Sadece garip. Bunun bir yolu, stdout'u stderr ile değiştirmektir , böylece arama sonuçları stderr'de ve hatalar stdout'tadır, daha sonra grep
filtreleme için stdout'u boruya bağlamaktır :
find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'
Genellikle find
başlangıç noktaları (genellikle dizinler olan arama yapılacak yerler) ve tahminler (testler ve eylemler) gibi argümanlar iletirsiniz . Bunlar args
yukarıdakilerin yerine geçer.
Bu , takas etmek istediğiniz iki standart akıştan birini tutmak için yeni bir dosya tanımlayıcı getirerek , takas etmek için yeniden yönlendirmeler gerçekleştirerek ve yeni dosya tanımlayıcıyı kapatarak çalışır.
3>&1
dosya tanımlayıcı 3'ü stdout'a yönlendirir, böylece stdout (dosya tanımlayıcı 1) daha sonra yeniden yönlendirildiğinde orijinal stdout yine de kolayca yazılabilir.1>&2
stdout'u stderr'a yönlendirir. Dosya tanımlayıcı 3 hala orijinal stdout olduğundan, yine de erişilebilir.2>&3
stderr'ı orijinal stdout olan dosya tanımlayıcı 3'e yönlendirir.3>&-
artık gerekli olmayan dosya tanımlayıcı 3'ü kapatır.Bununla birlikte, bu yöntemin dezavantajı, arama sonuçlarının stderr'e ve hataların stdout'a gönderilmesidir . Bu komutu doğrudan etkileşimli bir kabukta çalıştırıyorsanız ve çıktıyı daha fazla boruya geçirmiyor veya yönlendirmiyorsanız, bu gerçekten önemli değil. Aksi takdirde, bir sorun olabilir. Bu komutu bir komut dosyasına koyarsanız ve daha sonra birisi (belki de daha sonra) çıktısını yeniden yönlendirir veya yönlendirirse, beklendiği gibi davranmaz .
Çözüm, çıktıyı filtreledikten sonra akışları geri takmaktır . Yukarıda gösterilen aynı yönlendirmeleri boru hattının sağ tarafına uygulamak bunu başaramaz, çünkü |
sadece borular kesilir, böylece boru hattının yan kısmı yalnızca orijinal olarak stderr'a gönderilen (akışlar değiştirildiğinden) çıktı alır stdout çıktı. Bunun yerine, (
)
yukarıdaki komutu bir alt kabukta ( ilgili ) çalıştırmak için kullanabilir , ardından takas yönlendirmelerini uygulayabilirsiniz:
(find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
Bu işi yapan alt grup değil, gruplaşmadır. İsterseniz şunları kullanabilirsiniz {
;}
:
{ find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'; } 3>&1 1>&2 2>&3 3>&-
Bash'i destekleyebilen sistemlerde (Ubuntu gibi GNU / Linux sistemleri dahil) dahil olmak üzere bazı kabuklar, bir komut çalıştırmanıza ve akışlarından birine / yönlerinden yönlendirmenize izin veren işlem ikamesi yapmanızı sağlar. Sen yönlendirebilirsiniz find
a komutun Stderr grep
bunu filtreler komuta ve bu yönlendirme grep
stderr'e komutun stdout'u.
find args 2> >(grep -Fv 'Permission denied' >&2)
Bu fikir için kredi Android Dev'e gidiyor .
1>&2
. Kullandığım >&2
, eşdeğerdir ( ilgili ). Hangisini istersen kullan.Her ne kadar bash
destekler ikame işlemek, sh
Ubuntu olduğu dash
değil, hangi. Bu yöntemi kullanmaya çalışırsanız size "Sözdizimi hatası: yeniden yönlendirme beklenmedik" verirken, stdout ve stderr'i değiştirme yöntemi yine de çalışır. Ayrıca, POSIX modundabash
çalışırken , işlem değiştirme desteği kapatılır.
bash
POSIX modunda çalıştığı durumlardan biri , sh
1 olarak çağrılmasıdır . Bu nedenle, Fedora gibi bir işletim sisteminde bash
sağlar /bin/sh
veya yaptıysanız /bin/sh
sembolik bağın noktasını bash
Ubuntu kendiniz, süreç ikamesi hala iş yok sh
POSIX modu kapatmak için bir önceki komutun olmadan, senaryo. Senaryoya bu yöntemi kullanmak istiyorsanız Yapabileceğiniz en iyi şey, koymaktır #!/bin/bash
üstündeki yerine #!/bin/sh
zaten değilseniz,.
1 : Bu durumda, başlatma komut dosyalarındaki komutları çalıştırdıktan sonrabash
POSIX modunu otomatik olarak açar.
Bu komutları test etmek yararlıdır. Bunu yapmak için tmp
, geçerli dizinin bir alt dizini oluşturmak ve bir "İzin reddedildi" hatası tetiklemek için bunlardan birinden izin alarak bazı dosya ve dizinlerle doldurmak find
.
mkdir tmp; cd tmp; mkdir a b c; touch w a/x 'a/Permission denied messages.txt' b/y c/z; chmod 0 b
Dizinleri biri olan erişilebilir adında "İzin verilmedi" uzantılı bir dosya içerir. Koşu find
yönlendirmeler veya borular gösterileriyle bu dosyayı, aynı zamanda gerçek bir dizin için hata "İzin verilmedi" gösteriyor değil erişilebilir:
ek@Io:~/tmp$ find
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: ‘./b’: Permission denied
Hem stdout hem de stderr'i boruya bağlamak grep
ve "İzin reddedildi" içeren satırları filtrelemek, hata mesajını ortadan kaldırır, ancak adında bu ifadeye sahip dosya için arama sonucunu gizler:
ek@Io:~/tmp$ find |& grep -Fv 'Permission denied'
.
./a
./a/x
./c
./c/z
./w
./b
find 2>&1 | grep -Fv 'Permission denied'
eşdeğerdir ve aynı çıktıyı üretir.
"İzin reddedildi" ifadesini filtrelemek için yukarıda gösterilen yöntemler, yalnızca hata iletilerinden (arama sonuçlarından değil) başarılıdır. Örneğin, stdout ve stderr'ın değiştirildiği yöntem şöyledir:
ek@Io:~/tmp$ (find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find args 2> >(grep -Fv 'Permission denied' >&2)
aynı çıktıyı üretir.
Sen stderr'e gönderilen satırları sağlamak için farklı bir hata mesajı tetikleyebilir yok hala yoluyla izin verilir "İzin engellendi" metin içerirler. Örneğin, burada find
geçerli bir dizin ( .
) ile bir başlangıç noktası, ancak varolmayan dizin foo
başka bir ile çalıştırın:
ek@Io:~/tmp$ (find . foo 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: ‘foo’: No such file or directory
find
Standart Çıktının Hala Bir Terminal Olduğunu Kontrol EtmeAyrıca, hangi komutların yeni satırlar gibi özel karakterlerin tam anlamıyla görüntülenmesine neden olduğunu da görebiliriz. (Bu, yukarıdaki gösterimden ayrı olarak yapılabilir ve tmp
dizinde olması gerekmez .)
Adında yeni satır içeren bir dosya oluşturun:
touch $'abc\ndef'
Genellikle dizinleri başlangıç noktaları olarak kullanırız find
, ancak dosyalar da çalışır:
$ find abc*
abc?def
Başka bir komuta stdout'u Boru iki ayrı arama sonuçlarının yanlış bir izlenim yaratarak, yeni satır anlamıyla outputted neden olur abc
ve def
. Bunu aşağıdakilerle test edebiliriz cat
:
$ find abc* | cat
abc
def
Yalnızca stderr'i yeniden yönlendirmek bu soruna neden olmaz:
$ find abc* 2>/dev/null
abc?def
Ayrıca kapanmıyor:
$ find abc* 2>&-
abc?def
İçin Boru grep
yapar soruna neden:
$ find abc* |& grep -Fv 'Permission denied'
abc
def
(Değiştirme |&
ile 2>&1 |
eşdeğerdir ve aynı çıktı üretir.)
Stdout ve stderr takas ve çıkışı boru yapar değil problem nedeni find
'ın stdout'u olan stderr'yi halini değil borulu:
$ find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'
abc?def
Bu komutu gruplandırmak ve akışları geri değiştirmek soruna neden olmaz:
$ (find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
abc?def
( {
;}
Sürüm aynı çıktıyı üretir.)
Stderr'i filtrelemek için işlem ikamesi kullanmak da soruna neden olmaz:
$ find abc* 2> >(grep -Fv 'Permission denied' >&2)
abc?def