Jak wykluczyć / zignorować ukryte pliki i katalogi w wyszukiwaniu „znajdź” osadzonym za pomocą symboli zastępczych?


119

Począwszy od (zwróć uwagę na symbole wieloznaczne przed i po „pewnym tekście”)

find . -type f -name '*some text*'

jak można wykluczyć / zignorować wszystkie ukryte pliki i katalogi?

Już zbyt długo googlowałem, natknąłem się na trochę - śliwki i! (wykrzyknik) parametry, ale brak pasującego (i oszczędnego) przykładu, który właśnie działał .

Piping | do grepbyłby opcją i chętnie przyjmę też przykłady; ale przede wszystkim jestem zainteresowany krótkim jedną wkładką (lub kilku autonomicznych jednej wkładki, ilustrujących różne sposoby osiągnięcia tego samego celu w wierszu polecenia) tylko przy użyciu find.

ps: znajdowanie plików w systemie Linux i wykluczanie określonych katalogów wydaje się blisko powiązane, ale a) nie jest jeszcze akceptowane i b) jest powiązane, ale różne i różne, ale c) może dostarczyć inspiracji i pomóc w ustaleniu zamieszania!

Edytować

find . \( ! -regex '.*/\..*' \) -type f -name "whatever", Pracuje. Wyrażenie regularne szuka „wszystkiego, potem ukośnika, następnie kropki, a następnie wszystkiego” (tj. Wszystkich ukrytych plików i folderów, w tym ich podfolderów) oraz „!” neguje regex.


Nie pomaga w tym, o co prosiłeś w swojej edycji, ale spójrz na moje pytanie i jego odpowiedź tutaj: unix.stackexchange.com/q/69164/15760, a także link w odpowiedzi.

Odpowiedzi:


134

Spowoduje to wydrukowanie wszystkich plików, które są potomkami twojego katalogu, pomijając ukryte pliki i katalogi:

find . -not -path '*/\.*'

Więc jeśli szukasz pliku z some textjego nazwą i chcesz pominąć ukryte pliki i katalogi, uruchom:

find . -not -path '*/\.*' -type f -name '*some text*'

Wyjaśnienie:

-pathOpcja uruchamia sprawdza wzór przeciwko cały ciąg ścieżki. *jest symbolem wieloznacznym, /jest separatorem katalogu, \.jest kropką (musi być poprzedzony znakiem specjalnym, aby uniknąć specjalnego znaczenia) i *jest kolejnym znakiem wieloznacznym. -notoznacza, że ​​nie wybieraj plików pasujących do tego testu.

Nie sądzę, aby było findto wystarczająco inteligentne, aby uniknąć rekurencyjnego przeszukiwania ukrytych katalogów w poprzednim poleceniu, więc jeśli potrzebujesz prędkości, użyj -prunezamiast tego:

 find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f -name '*some text*' -print

Zauważ, że -printna końcu potrzebujesz tego na końcu! Również nie jestem pewien, czy -name '\.*' would be more efficient instead of -path` (ponieważ ścieżka szuka podścieżek, ale zostaną one przycięte)
artfulrobot

Jakie jest specjalne znaczenie .w tym kontekście?
frostschutz

@frostschutz Kropka po findoznacza bieżący katalog: findobejrzy wszystkie pliki i katalogi w bieżącym katalogu. Argument po pathjest wyrażeniem regularnym, w którym kropka zwykle oznacza „dowolny znak”, aby oznaczać dosłowną kropkę, musimy uciec przed nią odwrotnym ukośnikiem. Argument po -name nie jest wyrażenie regularne, ale rozszerza symbole wieloznaczne jak ?i *jak pocisk robi.
Flimm,

2
@frostschutz Właściwie, pomyśl o tym, mogę się mylić, .mając specjalne znaczenie.
Flimm,

1
@Flimm tak, nie musisz uciekać .. O ile mi wiadomo, tylko te muszą być uciekł: *, ?, i [].
thdoan

10

Jest to jeden z niewielu sposobów wykluczania plików kropek, który działa również poprawnie w systemach BSD, Mac i Linux:

find "$PWD" -name ".*" -prune -o -print
  • $PWD wydrukuj pełną ścieżkę do bieżącego katalogu, aby ścieżka nie zaczynała się od ./
  • -name ".*" -prune dopasowuje wszystkie pliki lub katalogi, które zaczynają się od kropki, a następnie nie schodzą
  • -o -printoznacza wydrukować nazwę pliku, jeśli poprzednie wyrażenie nic nie pasowało. Używanie -printlub -print0powoduje, że wszystkie inne wyrażenia nie są drukowane domyślnie.

Proszę wyjaśnić / opracować „niepokojąco skomplikowane”; odpowiedzi już udzielone i twoja odpowiedź wydaje się świadczyć przeciwnie ...?
orzechowe o natty

2
„alarmująco skomplikowane” jest prawdopodobnie przesadne. Przeredagowałem odpowiedź, aby przejść do sedna. Myślę, że odpowiedź, którą zamieściłem, jest trudna do zrozumienia i trudna do zobaczenia bez bardzo uważnego przeczytania strony podręcznika. Jeśli używasz tylko GNU find, istnieje więcej możliwych rozwiązań.
eradman

-o ... -printjest pomocny. Do mojego użytku mam teraz find ... '!' -name . -name '.*' -prune -o ... -print, co było wygodniejsze niż włączenie $ PWD.
Roger Pate,

4
find $DIR -not -path '*/\.*' -type f \( ! -iname ".*" \)

Nie obejmuje wszystkich ukrytych katalogów i ukrytych plików w katalogu $ DIR


To idealna odpowiedź. Rekurencyjnie wyszukuje wszystkie pliki, ale wyklucza elementy zamówienia dla katalogów i plików ukrytych. Dzięki!
KyleFarris,

2

Odpowiedź I pierwotnie opublikowany jako „edit” do mojego pierwotnego pytania powyżej:

find . \( ! -regex '.*/\..*' \) -type f -name "whatever", Pracuje. Wyrażenie regularne szuka „wszystkiego, potem ukośnika, następnie kropki, a następnie wszystkiego” (tj. Wszystkich ukrytych plików i folderów, w tym ich podfolderów) oraz „!” neguje regex.


Podobne, ale tylko dla bieżącego folderu:find . \( ! -regex './\..*' \) -type f -maxdepth 1 -print
phyatt

2

Nie musisz do tego używać find. Wystarczy użyć globstar w powłoce samodzielnie, na przykład:

echo **/*foo*

lub:

ls **/*foo*

gdzie **/reprezentuje dowolny folder rekurencyjnie i *foo*każdy plik, który ma foow swojej nazwie.

Domyślnie użycie lsspowoduje wydrukowanie nazw plików z wyłączeniem ukrytych plików i katalogów.

Jeśli nie masz włączonego globowania, zrób to shopt -s globstar.

Uwaga: Nowa opcja globowania działa w powłokach Bash 4, zsh i podobnych.


Przykład:

$ mkdir -vp a/b/c/d
mkdir: created directory 'a'
mkdir: created directory 'a/b'
mkdir: created directory 'a/b/c'
mkdir: created directory 'a/b/c/d'
$ touch a/b/c/d/foo a/b/c/d/bar  a/b/c/d/.foo_hidden a/b/c/d/foo_not_hidden
$ echo **/*foo*
a/b/c/d/foo  a/b/c/d/foo_not_hidden

5
Nie potrzebujesz lstego! echo **/*foo*
Kevin Cox

@kenorb (i @ kevin-cox). Czy możesz być trochę bardziej gadatliwy? Dlaczego globstar (= *) miałby tutaj działać i jak? Co robi slash / robi?
orzechowy o natty

@nuttyaboutnatty /oznacza folder, oddziela katalogi od nazwy pliku. *w zasadzie reprezentuje wszystko.
kenorb

@kenorb tak-ale: jak ten jednowarstwowy pomaga w pierwotnym pytaniu?
wariat o natty

1
@nuttyaboutnatty Wyjaśniono i dodano przykład. Pomaga w znajdowaniu plików ignorujących ukryty.
kenorb

1

@ Flimm za odpowiedź jest dobra, szczególnie dlatego, że zapobiega znaleźć z malejącym do ukrytych katalogów . Wolę to uproszczenie:

Ogólnie, aby wykluczyć wszystkie ukryte ścieżki (zwykłe pliki, katalogi itp.):

find <start-point> -path '*/.*' -prune -o <expression> -print

Na przykład, używając katalogu roboczego jako punktu początkowego i -name '*some text*'jako wyrażenia:

find . -path '*/.*' -prune -o -name '*some text*' -print

W przeciwieństwie do tego, co sugeruje odpowiedź @ Flimm, brak ukrytych plików lub ukrytych katalogów to prosty przypadek. -path '*/.*'Wyrażenie jest prawdziwe dla każdej ścieżki (zwykłych plików, katalogów, itp), który ma .natychmiast po separatorze plików /. Ta linia przycina zarówno ukryte pliki, jak i katalogi.

Zezwalanie na ukryte pliki, z wyłączeniem ukrytych katalogów, wymaga dalszego filtrowania. W tym miejscu należy -type duwzględnić przycinane wyrażenie.

find <start-point> -type d -path '*/.*' -prune -o <expression> -print 

Na przykład:

find . -type d -path '*/.*' -prune -o -name '*some text*' -print

W tym przypadku -type d -path '*/.*'dotyczy truetylko katalogów, dlatego przycinane są tylko katalogi.


0

findma zgrabne przełączniki logiczne, takie jak, -andi -notmożesz użyć ich na swoją korzyść, aby znaleźć pasujący plik z dwiema podobnymi regułami:

$ touch non_hidden_file.txt .hidden_file.txt somethings/.another_hidden_file.txt                                                 

$ find . -type f -name '*hidden_file*' -and \( -not -name ".*" \)                            
./non_hidden_file.txt

Jak widać, findwykorzystuje dwie reguły -name '*hidden_file*'i -and \( -not -name ".*" \)znajduje te nazwy plików, które pasują do obu warunków - nazwa pliku z hidden_filenim, ale bez kropki. Zwróć uwagę na ukośniki przed nawiasami - służą one do zdefiniowania nawiasów jako findargumentów raczej definiujących podpowłokę (co inaczej nawiasy oznaczają bez ukośników)


0
$ pwd
/home/victoria

$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2

$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2

Uwagi:

  • . : bieżący folder
  • usuń, -maxdepth 1aby wyszukać rekurencyjnie
  • -type f: znajdź pliki, a nie katalogi ( d)
  • -not -path '*/\.*' : nie wracaj .hidden_files
  • sed 's/^\.\///g': usuń poprzedni ./z listy wyników
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.