Wie verwende ich den Befehl find, um Dateinamen aufzulisten, aber keinen Pfad?

Jan 06 2021

Ich habe einige Antworten online überprüft, aber sie funktionieren nicht, wenn -nameder Befehl einen Parameter enthält (möglicherweise mache ich etwas falsch, nicht sicher). Was ich tun möchte, ist, nur Dateinamen aufzulisten (nicht das Verzeichnis / den Pfad), und um es noch komplizierter zu machen, habe ich denselben Dateinamen mit unterschiedlicher Erweiterung, daher muss ich das Ergebnis mit -nameund filtern. -oDas Problem sind die Vorschläge, die ich mache Säge verwenden entweder -printfoder basename, und die funktionieren nicht gut, wenn es gibt -name *.txt -o name *.pdf. Gibt es eine andere Möglichkeit, dieses Problem zu lösen?

Beispiel meiner Dateien:

/dir1/dir2/dir3/dir4/
                    /file1.txt
                    /file1.pdf
                    /file1.ods ...etc.

Ich bin nur daran interessiert, einen oder mehrere Dateitypen pro Eintrag aufzulisten (indem -nameich meine Ergebnisse filtere.

Ist es möglich, dies mit nur einem findBefehl auszuführen, oder muss ich dies in zwei Schritten tun (Speichern des Ergebnisses in einer temporären Datei, dann Filtern / Entfernen des Verzeichnisses aus der temporären Datei)? Das Ergebnis, das ich erreichen möchte, ist eine Textdatei mit dem Dateinamen pro Zeile:

file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.

Der Befehl, den ich verwendet habe, ist

find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"

Ich benutze GNU find.

Aktualisieren

Es stellte sich heraus, dass ich setzen muss \(...\), wie von αғsнιη erinnert

Antworten

3 αғsнιη Jan 06 2021 at 21:02

Wenn Sie mehrere Ausdrücke im logischen ODER-Modus verwenden -o, müssen Sie sie alle einschließen \( ... \). Andernfalls wird das Ergebnis des letzten Ausdrucks immer berücksichtigt. und -printf '%f\n'wird verwendet, um den Dateinamen nur zu drucken, wenn führende Verzeichnisse entfernt wurden.

find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'

Siehe man findunter OPERATORS Abschnitt über ( expr ):

BETREIBER
...

(Ausdruck)
Vorrang erzwingen . Da Klammern für die Shell etwas Besonderes sind, müssen Sie sie normalerweise in Anführungszeichen setzen.

Sie können also entweder \( ... \)oder '(' ... ')'(Leerzeichen nach und vor Klammern sind wichtig) verwenden, um ihnen zu entkommen.

1 Kusalananda Jan 06 2021 at 22:58

Wie bereits erwähnt, müssen Sie Ihre -nameTests in Klammern gruppieren . Diese Klammern müssen \( ... \)als z. B. '(' ... ')'zum Schutz vor der Shell (wo sie sonst eine Subshell bezeichnen würden) maskiert oder zitiert werden .

Verwenden von Standard findund Vereinfachen der Handhabung der Dateinamensuffixe:

set -- txt pdf ods

for suffix do
    set -- "$@" -o -name "*.$suffix"
    shift
done
shift

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;

Dies setzt zuerst die Positionsparameter auf die Liste der Dateinamensuffixe, die wir sehen möchten (dies könnte auch von der Befehlszeile übernommen werden, wenn dies ein Skript ist), und erstellt die ODER-Liste der -nameTests. Dies wird dann in der findBefehlszeile verwendet.

Der findBefehl selbst ruft dann das basenameDienstprogramm für jeden gefundenen Namen auf.

Alternativ könnten wir stattdessen eine Parametersubstitution verwenden, um alle bis auf die Dateinamenkomponente jedes Pfadnamens zu entfernen. Dazu müssen wir die Pfadnamen jedoch an ein Inline- sh -cSkript übergeben:

# [...] as before [...]

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
    for pathname do
        printf "%s\n" "${pathname##*/}"
    done' sh {} +

Ich würde erwarten, dass dies schneller abläuft als die Variation mit basename, zumindest wenn viele Dateinamen zu verarbeiten sind, obwohl Sie mit GNU basenamevon coreutils Folgendes verwenden könnten -aoder --multiplemögen:

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +

Dies würde basenameso wenig wie möglich aufrufen . Wenn Sie jedoch Coreutils installiert haben, haben Sie möglicherweise auch Findutils mit GNU findund können -printf '%f\n'das Gleiche tun.