'Erişim engellendi' Hatlarını Çıkarma


9

Dizindeki findtüm pdf dosyalarını görmek için kullandığımda /homegö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:


19

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.


3
Grrr, insanlar neden hep 30 saniye beni dövüyor? : \
YouAGitForNotUsingGit

find: “/home/ihsan/.gvfs”: erişim reddedildi find: “/home/ihsan/.dbus”: erişim reddedildi, ~
solfish

bunun için yanlış bir şey var mı? evet ben de test etmek için benim tarafımdan oluşturulan diğer kullanıcılar ana dizin istiyorum
solfish

2
@solfish Bildiğim kadarıyla bu dosyaların size ait olması gerekir. Sen isteyebilirsinizsudo chown $USER: ~/.gvfs ~/.dbus
Zanna

1
Stderr'ı kapatmak yeterli olmalıdır 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.
David Foerster

8

Reddedilen erişim muhtemelen stderryerine yazdırılıyor stdout.

Bunu dene:

find /home -iname "*.pdf" 2>&1 | grep -v "access denied"

2>&1Çıktıyı yönlendirir stderriçin stdoutböylece grep -vişini yapabilir. (Varsayılan olarak, |yalnızca borular stdoutdeğil stderr.)


ama bu 2> & 1 için stderr varsa stdout'a gönderilsin mi?
solfish

@solfish Yup, işte tam da bu nokta :)
YouAGitForNotUsingGit

anlamadığım şey önce "|" çıktı olarak; sadece stderr var değil mi? ve sonra "|" girdi olarak bunu aldık
solfish

@solfish Bu soruna yaklaşık bir buçuk yıl önce rastladım ve farklı bir yöntem kullanarak sorunu çözebildim . Ama sonra cevabımın altındaki bir yorum basitçe kullanılmasını önerdi 2>&1... Ben bash uzmanı değilim, bu yüzden yanlışsa lütfen bunu söyleyin :)
YouAGitForNotUsingGit

@AndroidDev Bu cevaba alternatif olarak bu farklı yöntemi eklemenizi öneririm. Etan Reisner'in eleştirisi , süreç ikamesinin taşınabilir olmadığıydı. Ancak bashUbuntu'da POSIX modu hariç . Bence en iyi çözüm - kötü amaçlı olarak adlandırılmış bir dosya access deniedhala görünecektir.
Eliah Kagan

4

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 findistersiniz. 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.

En Yaygın Yöntemler ve Sınırlamaları

İ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/nullveya 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, findbir başlangıç ​​noktası yoksa "Böyle bir dosya veya dizin yok" bildirir. Birden fazla başlangıç ​​noktasıyla, findyine de bazı yararlı sonuçlar döndürebilir ve çalışıyor gibi görünebilir. Örneğin, eğer ave cmevcut ama bdoes not, find a b c -name xiçinde baskılar sonucu a, sonra "Hayır böyle bir dosya veya dizini" bin 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 findolan -printeylem 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 .

  • O Eğer değil bir terminal, daha sonra dosya adları bunlar terminali davranışını değiştirebilir satırbaşıyla ve kontrol karakterleri gibi garip karakterler içeren olsa bile olduğu gibi çıkış vardır. O takdirde ise bir terminal, daha sonra bu karakterler giderilmiş ve ?yerine yazdırılır.
  • Bu genellikle istediğiniz şeydir. Dosya adlarını daha fazla işleyecekseniz, bunların tam anlamıyla çıktısı alınmalıdır. Ancak, bunları görüntüleyecekseniz, yeni satır içeren bir dosya adı birden çok dosya adını taklit edebilir ve arka boşluk karakterleri dizisi içeren bir dosya adı farklı bir ad gibi görünebilir. Terminalinizdeki renkleri değiştiren kaçış dizileri içeren dosya adları gibi başka sorunlar da mümkündür.
  • Ancak arama sonuçlarının başka bir komutla (ör. grep) Aktarılması, findartı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 findterminalin bir tür maskaralığına maruz kalırsınız algılama amaçlıdır.
  • man findDosya 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 findUbuntu dahil GNU / Linux sistemlerinde uygulanması.

Standart Hatası Filtrelerken Standart Çıktıyı Yalnız Bırakma

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 grepfiltreleme için stdout'u boruya bağlamaktır :

find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'

Genellikle findbaşlangıç ​​noktaları (genellikle dizinler olan arama yapılacak yerler) ve tahminler (testler ve eylemler) gibi argümanlar iletirsiniz . Bunlar argsyukarı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.

  • İçerik tanımlayıcı 1 stdout'u ve 2 Stderr (ve unredirected 0 olan standart giriş ). Ancak diğer dosya tanımlayıcılarını kullanarak da yeniden yönlendirebilirsiniz. Bu, bir dosyayı veya cihazı açmak veya açık tutmak için kullanılabilir.
  • 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>&2stdout'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.
  • Daha fazla bilgi için bkz. Stdout değil stderr nasıl borulanır? ve IO Yönlendirme - Stdout ve stderr (Gelişmiş) ve özellikle bir stderr'ı bir filtreden geçirerek değiştirin .

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>&-

Daha Az Zorlu Bir Yol: Süreç Değişimi

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 finda komutun Stderr grepbunu filtreler komuta ve bu yönlendirme grepstderr'e komutun stdout'u.

find args 2> >(grep -Fv 'Permission denied' >&2)

Bu fikir için kredi Android Dev'e gidiyor .

Her ne kadar bash destekler ikame işlemek, shUbuntu olduğu dashdeğ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.

bashPOSIX modunda çalıştığı durumlardan biri , sh1 olarak çağrılmasıdır . Bu nedenle, Fedora gibi bir işletim sisteminde bashsağlar /bin/shveya yaptıysanız /bin/shsembolik bağın noktasını bashUbuntu kendiniz, süreç ikamesi hala iş yok shPOSIX 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/shzaten değilseniz,.

1 : Bu durumda, başlatma komut dosyalarındaki komutları çalıştırdıktan sonrabash POSIX modunu otomatik olarak açar.

Bir örnek

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 findyö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 grepve "İ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 findgeçerli bir dizin ( .) ile bir başlangıç ​​noktası, ancak varolmayan dizin foobaş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

findStandart Çıktının Hala Bir Terminal Olduğunu Kontrol Etme

Ayrı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 tmpdizinde 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 abcve 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
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.