it-swarm.com.de

Bash-Globbing, das allen Dateien mit Ausnahme derjenigen mit einer bestimmten Erweiterung entspricht und für Dateinamen mit Punktzeichen funktioniert

Ich mache einige Sachen mit Audiodateien, die meisten, aber nicht alle sind MP3-Dateien. Jetzt möchte ich einige Befehle nur für Dateien ausführen, die keine MP3-Dateien sind, oder nur für Dateien, die keine Erweiterung .mp3 Haben.

Ich halte mich für ziemlich gut in regulären Ausdrücken, aber nicht so sehr in Dateiglobbing, was sich auf unerwartete Weise subtil unterscheidet.

Ich habe mich umgesehen und von anderen gelernt SO & SE antwortet, dass Bash "erweitertes Globbing" hat, was mir dies ermöglicht:

file ../foo/bar/*.!(mp3)

Aber einige meiner Dateinamen enthalten neben dem Punkt, der die Dateinamenerweiterung bildet, Punkte:

../foo/bar/Naked_Scientists_Show_19.10.15.mp3
../foo/bar/YWCS_ep504-111519-pt1_5ej4_41cc9320.mp3_42827d48daefaa81ec09202e67fa8461_24419113.mp3
../foo/bar/eLife_Podcast_19.09.26.mp3
../foo/bar/gdn.sci.080428.bg.science_weekly.mp3

Es scheint, dass der Globus vom ersten Punkt an übereinstimmt und nicht vom letzten Punkt. Ich habe mir die Dokumentation angesehen, aber es scheint, dass sie weit weniger leistungsfähig sind als Regexe. Aber ich habe nicht wirklich alles durchgeknallt, da ich nicht so viel Zeit mit * nix-Muscheln verbringe.

Habe ich irgendwie verpasst, dass ich das mit Bash Globbing noch machen kann? Wenn nicht, wäre es immer noch wert, einen Weg zu finden, um dasselbe mit find oder einem anderen Tool zu erreichen.

10
hippietrail

*.!(mp3) stimmt mit foo.bar.mp3 überein, da dies foo. ist, gefolgt von bar.mp3, was nicht mp3 ist.

Sie möchten hier !(*.mp3), was mit allem übereinstimmt, was nicht mit .mp3 Endet.

Wenn Sie Dateien abgleichen möchten, deren Name mindestens eine . Enthält (außer einer führenden, die sie zu einer versteckten Datei machen würde), aber nicht mit .mp3 Endet, können Sie !(*.mp3|!(*.*)).

18

Es gibt auch die Variable GLOBIGNORE :

Die Shell-Variable GLOBIGNORE kann verwendet werden, um den Satz von Dateinamen einzuschränken, die einem Muster entsprechen. Wenn GLOBIGNORE festgelegt ist, wird jeder übereinstimmende Dateiname, der auch mit einem der Muster in GLOBIGNORE übereinstimmt, aus der Liste der Übereinstimmungen entfernt. Wenn die Option nocaseglob gesetzt ist, wird der Abgleich mit den Mustern in GLOBIGNORE ohne Rücksicht auf den Fall durchgeführt. Die Dateinamen . Und .. Werden immer ignoriert, wenn GLOBIGNORE gesetzt und nicht null ist. Wenn Sie jedoch GLOBIGNORE auf einen Wert ungleich Null setzen, wird die Shell-Option dotglob aktiviert, sodass alle anderen Dateinamen, die mit "." Beginnen, übereinstimmen. Um das alte Verhalten beim Ignorieren von Dateinamen zu erhalten, die mit einem "." Beginnen, machen Sie ".*" Zu einem der Muster in GLOBIGNORE. Die Option dotglob ist deaktiviert, wenn GLOBIGNORE nicht gesetzt ist.

$ touch a.b.mp3 .c.mp3 foo.tgz .bar
$ echo *
a.b.mp3 foo.tgz
$ shopt -s extglob; echo *.!(mp3)
a.b.mp3 foo.tgz
$ GLOBIGNORE='*.mp3'; echo *
.bar foo.tgz
6
muru

der einfachste Weg, den ich mir vorstellen kann:

find ${path-to-folder} -type f  | grep -vE ".*\.mp3$"

Sie finden alle Dateien in einem Ordner und leiten sie an einen umgekehrten erweiterten grep weiter:

Finden Sie alle Dateien an einem Ort

find ${path-to-folder} -type f 

Grep umkehren und mit einem regulären Ausdruck nach Erweiterung filtern

grep -vE ".*\.mp3$"

Grep-Flaggen:

  • -v reverse grep

  • -E erweitertes grep (Verwendung von Regex)

Regex erklärte:

  • .* bedeutet von 0 bis zu jeder Zeichenanzahl, jedes mögliche Zeichen

  • \. sucht nach dem tatsächlichen Punkt

  • mp3 für die Zeichenfolge, die die Erweiterung bildet

  • $ steht für EOL

2
Kramer

Möglicherweise nicht ideal für Ihre Situation, aber ich habe mich gefragt, wie Sie eine Funktion in reinem Bash erstellen und dann die Erweiterung als Argument übergeben können. Dies kann nützlich sein, wenn Sie sie in Ihr bashrc einfügen möchten und Sie möchten in Zukunft dasselbe tun, wie im Folgenden

Im Grunde genommen machen wir also den Regex-Check für Ihre gewünschte Erweiterung.

for file in *; do
  if [[ $file =~ \.mp3$ ]]; then
    echo $file
  fi
done

Implementieren in einer Funktion: Dies würde alle Dateien mit einer bestimmten Erweiterung in Ihrem aktuellen Verzeichnis ausgeben.

getFileByExt(){
local extension="$1"
if (( $# == 1 )); then
for file in *; do
  if [[ $file =~ \.$extension$ ]]; then
    echo $file
  fi
done
else
  echo "Usage: ${FUNCNAME[0]} <extension>" 
## If run from bashrc, return the name of function
fi
}

Wenn Sie beispielsweise alle Dateien mit der Erweiterung mp3 Abrufen möchten, ist dies ganz einfach:

getFileByExt mp3

Und um Dateien ohne spezielle Erweiterung zu erhalten: Dies würde alle Dateien ausgeben, die keine bestimmte Erweiterung in Ihrem aktuellen Verzeichnis haben.

getFileWithoutExt(){
local extension="$1"
if (( $# == 1 )); then
for file in *; do
  if [[ ! $file =~ \.$extension$ ]]; then
    echo $file
  fi
done
else
  echo "Usage: ${FUNCNAME[0]} <extension>"
fi
}

Um Dateien ohne die Erweiterung mp3 Zu erhalten, gehen Sie einfach wie folgt vor:

getFileWithoutExt mp3

Für mehr Information:

https://stackoverflow.com/questions/407184/how-to-check-the-extension-of-a-filename-in-a-bash-script

https://stackoverflow.com/questions/18278990/easiest-way-to-check-for-file-extension-in-bash/1828035

1
Rakib Fiha