Chcę rekurencyjnie szukać każdego *.pdf
pliku w katalogu, ~/foo
którego podstawowa nazwa odpowiada nazwie katalogu nadrzędnego pliku.
Załóżmy na przykład, że struktura katalogów ~/foo
wygląda tak
foo
├── dir1
│ ├── dir1.pdf
│ └── dir1.txt
├── dir2
│ ├── dir2.tex
│ └── spam
│ └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf
Uruchomienie żądanego polecenia powróci
~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf
Czy jest to możliwe przy użyciu find
lub innego podstawowego narzędzia? Zakładam, że jest to wykonalne przy użyciu -regex
opcji, find
ale nie jestem pewien, jak napisać prawidłowy wzór.
Odpowiedzi:
Z GNU
find
:-regextype egrep
użyj wyrażenia regularnego w stylu egrep..*/
dopasuj dyrektywy dziadków.([^/]+)/
dopasuj katalog nadrzędny w grupie.\1\.pdf
służybackreference
do dopasowania nazwy pliku jako nadrzędnego reż.aktualizacja
Jeden (dla mnie jeden) może uważać, że
.*
jest wystarczająco chciwy, nie trzeba wykluczać/
z dopasowania rodziców:Powyższe polecenie nie będzie działać dobrze, ponieważ jest zgodne
./a/b/a/b.pdf
:.*/
mecze./
(.+)/
meczea/b/
\1.pdf
meczea/b.pdf
źródło
find . -regex '.*/\([^/]*\)/\1\.pdf'
wtedy to nawet działałoby z BSDfind
.Tradycyjny wariant pętli polegający na
find .. -exec sh -c ''
stosowaniu konstrukcji powłoki w celu dopasowania do nazwy basename i bezpośredniej ścieżki powyżej byłby do wykonania poniżej.Aby rozbić poszczególne rozszerzenia parametrów
file
zawiera pełną ścieżkę do.pdf
pliku zwróconego zfind
polecenia"${file##*/}"
zawiera tylko część po ostatniej,/
tj. tylko nazwę pliku pliku"${file%/*}"
zawiera ścieżkę do finału,/
tj. z wyjątkiem części wynikame w postaci basename"${path##*/}"
zawiera część za ostatnią/
zepath
zmiennej, tj. bezpośrednią ścieżkę folderu nad nazwą bazową pliku"${base%.*}"
zawiera część nazwy basenu z.pdf
usuniętym rozszerzeniemWięc jeśli basename bez rozszerzenia pasuje do nazwy bezpośredniego folderu powyżej, drukujemy ścieżkę.
źródło
Odwrotność odpowiedzi Iniana , tj. Poszukaj katalogów, a następnie sprawdź, czy przechowują plik o określonej nazwie.
Poniższe wypisuje ścieżki znalezionych plików względem katalogu
foo
:${dirpath##*/}
zostanie zastąpiony fragmentem nazwy pliku ścieżki katalogu i może zostać zastąpiony przez$(basename "$dirpath")
.Dla osób, które lubią składnię zwarciową:
Zaletą robienia tego w ten sposób jest to, że możesz mieć więcej plików PDF niż katalogów. Liczba zaangażowanych testów zostanie zmniejszona, jeśli ograniczy się zapytanie o mniejszą liczbę (liczbę katalogów).
Na przykład, jeśli pojedynczy katalog zawiera 100 plików PDF, próbowałoby to wykryć tylko jeden z nich, zamiast testować nazwy wszystkich 100 plików w stosunku do nazwy katalogu.
źródło
z
zsh
:Uważaj, że chociaż
**/
nie będzie podążać za dowiązaniami symbolicznymi, to*/
zrobi to.źródło
Nie został określony, ale oto rozwiązanie bez wyrażeń regularnych, jeśli ktoś jest zainteresowany.
Możemy użyć,
find . -type f
aby po prostu pobrać pliki, a następnie wykorzystaćdirname
ibasename
napisać warunek. Narzędzia mają następujące zachowanie:basename
zwraca tylko nazwę pliku po ostatnim/
:dirname
daje całą ścieżkę do finału/
:Dlatego
basename $(dirname $file)
podaje katalog nadrzędny pliku.Rozwiązanie
Połącz powyższe, aby utworzyć warunek
"$(basename $file)" = "$(basename $(dirname $file))".pdf
, a następnie wydrukuj każdy wynik,find
jeśli warunek zwróci true.W powyższym przykładzie dodaliśmy katalog / plik ze spacjami w nazwie, aby traktować tę sprawę (dzięki @Kusalananda w komentarzach)
źródło
Final Thesis.pdf
(ze spacją).Biorę bash masek, prosty pętli nad ciąg testuje każdy dzień nad Find programu. Nazwij mnie irracjonalnym, a choć może być nieoptymalny, taki prosty kod robi dla mnie pewną sztuczkę: czytelny i wielokrotnego użytku, nawet satysfakcjonujący! Pozwól mi zatem zasugerować kombinację:
• bash globstar :
for f in ** ; do ...
** pętle nad każdym plików w bieżącym katalogu i wszystkich podfolderów .. Aby sprawdzić status globstar w bieżącej sesji:shopt -p globstar
. Aby aktywować globstar:shopt -s globstar
.• Narzędzie „plikowe” :
if [[ $(file "$f") =~ pdf ]]; then ...
sprawdzanie aktualnego formatu pliku pdf - bardziej niezawodne niż testowanie tylko rozszerzenia pliku• basename, dirname : aby porównać nazwę pliku z nazwą katalogu znajdującego się bezpośrednio nad nim.
basename
zwraca nazwę pliku -dirname
zwraca całą ścieżkę do katalogu - połącz dwie funkcje, aby zwrócić tylko jeden katalog zawierający pasujący plik. Umieszczam każdy z nich w zmiennej ( _mydir i _myf ), aby następnie wykonać prosty test przy użyciu = ~ do dopasowania łańcucha.Jedna subtelność: usuń „kropkę” z nazwy pliku, aby uniknąć dopasowania nazwy pliku do bieżącego katalogu, którego skrót to także „.” - Użyłem bezpośredniego podstawienia łańcucha na zmiennej _myf :
${_myf//./}
- niezbyt elegancki, ale działa. Pozytywne wyniki powróci ścieżkę każdego pliku - wraz z pełną ścieżkę bieżącego folderu poprzedzając wyjście z:$(pwd)/
.Kod
źródło