Das Verschieben von Dateien mit "und * verursachte einen Fehler

Aug 22 2020

Ich habe Probleme beim Verschieben von Dateien in einem Bash-Skript. Ich habe verschiedene Lösungen ausprobiert, die ich hier gefunden habe, für dasselbe Problem, kann aber nichts finden, was funktioniert.

Mein letzter Versuch war das Hinzufügen, shopt -s dotglob nullglobaber das hat nichts gelöst.

In diesem Test

jdir0="/media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)"


mv -v "$jdir0/*" "$jdir0/subs/" &>> $debuglog

.. und ich bekomme:

mv: cannot stat '/media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/*': No such file or directory

aber ja, das gibt es!

drwxrwx--- 1 root vboxsf   4096 Aug 22 07:06  ../
-rwxrwx--- 1 root vboxsf      0 Aug 21 17:19 'kallee.(222)..nnn.srt'*
-rwxrwx--- 1 root vboxsf 159363 Aug 21 17:26 'movie.test(2929).ismim.mp4'*
drwxrwx--- 1 root vboxsf      0 Aug 22 07:06  subs/

(Der Grund, warum die Namen wirklich seltsam sind, ist, dass ich vor dieser Funktion teste, um ungültige Zeichen zu entfernen)

Update: Anscheinend habe ich zeitweise Fehler bekommen, und ich habe es schließlich nach Tagen auf ein Serverproblem zurückgeführt (wo die Dateien gespeichert wurden). Anscheinend traten diese Fehler auf, wenn der Server mit der Änderung von Speichern / Name nicht fertig war und das Skript ihn aufforderte, etwas Neues zu tun. Beispiel: Benennen Sie die Datei A in B um und bitten Sie sie, B in C umzubenennen, BEVOR der Server die erste Anforderung ausgeführt hat. Dies führte dazu, dass der Server sagte: B existiert nicht, was natürlich einen Fehlercode verursachte.

Antworten

7 StéphaneChazelas Aug 22 2020 at 05:44

*ist ein Glob-Operator der Shell. Es muss nicht zitiert werden, um als solches erkannt zu werden. Wenn es zitiert wird, /media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/*wird es buchstäblich an die aufgerufene Datei übergeben mvund mvversucht, diese zu verschieben *, und es gibt keine solche Datei.

Also brauchst du:

mv -v -- "$jdir0"/* "$jdir0/subs/" >> "$debuglog" 2>&1

Damit die Shell "$jdir0"/*vor dem Aufruf in die Liste der übereinstimmenden Dateien erweitert wird mv.

Sie möchten hier nichtnullglob , da dies bedeuten würde, dass in Abwesenheit von Dateien, die diesem "$jdir0"/*Muster entsprechen, mvmit just aufgerufen -vwird --und media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/subs/ein verwirrender Syntaxfehler durch verursacht wird mv.

failglobIn diesem Fall ist es möglicherweise besser, den Befehl abzubrechen, wenn die Globs nicht übereinstimmen. Beachten Sie jedoch, bashdass der Vorgang in diesem Fall abhängig vom Kontext, in dem der Befehl aufgerufen wird, auf inkonsistente Weise abgebrochen wird, was die Verwendung dieser Option in Skripten schwierig macht.

dotglob ist es, Globs zu erlauben, versteckte Dateien abzugleichen.

Beachten Sie nun, dass Globs unabhängig von ihrem Typ¹ mit Dateien übereinstimmen, sodass auch die *oben genannten übereinstimmen subs. Wenn subses sich um einen Symlink zu einem Verzeichnis handelt, mvwird dieser subsSymlink gerne in dieses Verzeichnis verschoben , wodurch alle nachfolgenden Verschiebungen fehlschlagen, da das subsZielverzeichnis jetzt nicht mehr vorhanden ist. Wenn subses sich um ein einfaches Unterverzeichnis handelt, mvwird sich wahrscheinlich beschweren, dass es kein Verzeichnis in sich selbst verschieben kann.

Vielleicht möchten Sie es stattdessen schreiben:

shopt -s extglob
mv -v -- "$jdir0"/!(subs) "$jdir0/subs/" >> "$debuglog" 2>&1

Wo !(pattern)ist der erweiterte Glob-Operator ksh, der mit einem Dateinamen übereinstimmt , der nicht übereinstimmt pattern? Verschieben Sie hier also eine beliebige Datei, aber subs.

Beachten Sie auch, dass in der bashShell Parametererweiterungen auch in Umleitungszielen angegeben werden müssen, selbst in nicht interaktiven Shell-Instanzen (außer wenn sich bash im POSIX-Modus befindet).


¹ es sei denn, Sie verwenden zsh anstelle von bash und seinen Glob-Qualifikationsmerkmalen *(.), um nur reguläre Dateien zu verschieben