Ich habe heute während meiner Mittagspause ein Bash-Skript geschrieben, das in einem Verzeichnis nach Dateien ohne Erweiterung sucht und diesen Dateien eine Dateierweiterung anhängt.
Das Skript ist relativ lang, weil ich eine Menge Flags und Sachen wie Verzeichnisauswahl hinzugefügt habe und ob die Datei kopiert oder überschrieben werden soll, aber die grundlegende Funktionalität kann einfach wie folgt repliziert werden:
#recursively find files in current directory that have no extension
for i in $(find . -type f ! -name "*.*"); do
#guess that extension using file
extfile=$(file --extension --brief $i)
#select the first extension in the event file spits something weird (e.g. jpeg/jpe/jfif)
extawk=$(echo $extfile | awk -F/ '{print $1}')
#copy the file to a file appended with the extension guessed from the former commands
cp -av $i $i.$extawk
done
In meinem eigentlichen Skript ist es etwas ordentlicher – ich wollte die Befehle hier nur aufteilen, damit ich kommentieren kann, warum ich Dinge mache.
Meine Frage: Die Verwendung find
in Kombination mit file
in der von mir gewählten Weise ist wahrscheinlich nicht die sicherste Methode, dies zu tun – was ist dieam bestenMöglichkeit, Erweiterungen für eine große Gruppe unterschiedlicher Dateitypen in mehreren Verzeichnissen rekursiv zu erraten und anzuhängen?
Antwort1
for x in $(find …)
scheitert mitDateinamen, die Leerzeichen (häufig) oder Platzhalterzeichen (eher ungewöhnlich) enthalten. Analysieren Sie niemals die Ausgabe von find
. Verwenden Sie -exec
.
Zsh'Szmv
ist praktisch für die Massenumbenennung.
Lassen Sie uns einen zmv-Befehl konstruieren, der das tut, was Sie wollen. Lassen Sie uns zuerst das Suchmuster erstellen:
autoload zmv
zmv -C -o -a -n -Q '(*/)#^*.*(.)' …
-C
bewirkt, dass Dateien kopiert statt verschoben werden.-o -a
geht über-a
ancp
.-n
bedeutet, nicht zu handeln, sondern nur zu drucken, was getan werden soll. Entfernen Sie es, wenn Sie zufrieden sind. Ersetzen Sie es durch „-v
wenn Sie handeln, aber auch drucken möchten, was getan wird“.-Q
ermöglichtGlob-Qualifikationim Muster.(*/)#
trifft auf null oder mehr Verzeichnisse zu. Es verwendet die#
Glob-Operator(extended_glob
ist in zmv immer aktiviert).^*.*
verwendet den Glob-Operator, um Dateien ohne „a“ im Namen^
abzugleichen ..
(.)
ist ein Glob-Qualifizierer, der die Übereinstimmungen auf reguläre Dateien beschränkt.…
wird durch den Ersatztext ersetzt. Dieser kann verwendet werden,$f
um auf den Originalnamen zu verweisen.
zmv
berechnet alle Ersatznamen, bevor ein Ersatz durchgeführt wird, und meldet sich, wenn bereits ein Ersatzname vorhanden ist oder es Konflikte gibt. Dateien, deren Ersatzname mit dem Original identisch ist, werden übersprungen.
Lassen Sie uns nun den Ersatztext erstellen. Wir werden viel verwendenParametererweiterungMerkmale.
file
Verlängerung beantragen :$(file --extension --brief -- $f)
.
Stellen Sie zur Vorbereitung des Ersatzes ein voran :$(echo -n .; file --extension --brief -- $f)
(Dies könnte alternativ mit der Parametererweiterung erfolgen:${:-.$(…)}
.)- Wenn mehrere vorgeschlagene Erweiterungen (durch Schrägstriche getrennt) vorhanden sind, behalten Sie nur die erste:
${$(echo -n .; file --extension --brief -- $f)%%/*}
- Wenn die vorgeschlagene Erweiterung leer oder ist
???
, geben Sie auf (ersetzen Sie.
oder.???
durch eine leere Zeichenfolge):${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}
- Hängen Sie die hinzugefügte Erweiterung an
$f
(den ursprünglichen Namen) an. Wenn das, was wir anhängen, leer ist, bleibt die Datei unverändert.
Der resultierende Befehl:
zmv -C -o -a -n -Q '(*/)#^*.*(.)' '$f${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}'
Dies ist etwas kryptisch und Sie ziehen es möglicherweise vor, den Code zum Generieren des Ersatzes in eine Funktion einzufügen und zu verwenden zmv … '$(add_extension $f)'
.
Antwort2
Der effektivste Weg besteht meiner Meinung nach darin, die MIME-Typen der Datei mit der Datenbank unter zu vergleichen /usr/share/mime/globs
.
- Klumpenin Linux sindDateierweiterung. Beispiel angegeben, Ausgabe vonGlobs-Datei
application/x-mswinurl:*.url
text/x-mrml:*.mrl
text/x-erlang:*.erl
audio/x-pn-audibleaudio:*.aa
application/x-bzip-compressed-tar:*.tbz2
application/x-netshow-channel:*.nsc
application/x-hdf:*.h4
application/pgp-keys:*.key
text/x-idl:*.idl
text/x-chdr:*.h
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.visio:*.vsd
application/x-hdf:*.h5
video/vnd.mpegurl:*.m4u
- nach der Beschreibung des Typs example -->
text/x-erlang
weist es Linux an, alle Dateien*.
alsErlangmit der Erweiterung.erl
[glob], deshalb -->*.erl
/etc/magic
Sie können Ihre eigenen Erweiterungen hinzufügen, die in der Datei berücksichtigt werden
Führen Sie daher den folgenden Befehl aus:
mimetype -bM file
b
Argument für „zeig es dir einfachtype-app/extension
“ (kurz)M
Argument bedeutetMagieist die Art und Weise, wie Linux die Dateien im Bytecode, hexadezimal und binär prüft, um zu verifizieren, dass die Dateien wirklich das sind, was sie vorgeben zu sein.Mime Typgibt nicht
/jpg/png/webp
nur einen Typ zurück und dieser ist kürzer alsfile --mime-type file
Kehrt zurück:
image/webp
abschließende Gedanken
mimetype
funktioniert am besten mitBinärdateienwie PDFs, Bilder, Videos. Das liegt daran, dass es die Binärdatei prüfen kann, anstatt text plain
nur das zu tun, und Sie müssen sich mit etwas identifizieren, und das ist komplizierter, deshalb können Texteditoren verschiedene Programmiersprachen erkennen, es braucht die Hilfe des Benutzers und eine Serversprache für jede Programmiersprache.
für Rekursion, denke ichBaumist gut:
tree -FIi '*.*' | grep -v /$
- Argument ist , [Schrägstrich] zu Verzeichnissen
F
hinzuzufügen , Beispiel, →/
folder
folder/
- Argument
I
ist, das Gegenteil des Musters auszuwählen*.*
[das heißt, alle Dateien mit der Erweiterung auszuwählen], also ist das Gegenteil nicht die Erweiterung - Das Argument
i
besteht darin, Leerzeichen aus der Baumausgabe zu entfernen grep -v
ist die Auswahl umgekehrt, deshalb fügen Sie das/
Argument -F hinzu zuBaumBefehl am Anfang, damit Sie Verzeichnisse entfernen und nur Dateien abrufen können, mit/$
.
Weitere Informationen finden Sie hierMIME-Typen