Mit mv
cannot move 'foo' to a subdirectory of itself
ist in diesem Fall harmlos, Sie können es ignorieren. Ich meine, ich mv
werde den Rest trotz der Warnung verschieben. Der Exit-Status ist jedoch nicht der Fall 0
. Dies kann ein großes Hindernis in Skripts sein, bei denen Sie abbrechen möchten oder eine Korrekturaktion durchführen möchten, falls mv
dies nicht erfolgreich ist.
Dies ist bereits in einem Kommentar gesagt worden : Sie können zum Schweigen bringen, mv
indem Sie stderr mit umleiten 2>/dev/null
. Andere Warnungen oder Fehler werden jedoch ebenfalls umgeleitet.
Ich denke, Sie können das Muster nicht einfach "verfeinern, um die Quelle auf Dateien und nicht auf Verzeichnisse zu beschränken". Trotzdem können Sie einen Ansatz wählen, der nicht mit dem Literal übereinstimmt foo
. Der folgende Ansatz hat nichts mit Dateien oder Verzeichnissen zu tun. Nur mit Namen, weil Globs sich mit Namen beschäftigen; In manchen Fällen reicht es möglicherweise nicht aus.
Der *foo*
Glob entspricht vier disjunktiven Objekten:
foo
selbst- foo nur mit Präfix, wie
bar-foo
- du kannst sie nach anpassen*?foo
- Foo mit Präfix und Postfix, wie
bar-foo-baz
-*?foo?*
- foo nur mit postfix, wie
foo-baz
-foo?*
Um dies auszuschließen foo
, brauchen Sie nur die letzten drei (2-4), so dass der erste Ansatz sein kann:
mv *?foo *?foo?* foo?* foo/
Wenn Sie nicht die nullglob
Shell-Option festgelegt haben, muss jedes Muster mit einem bestimmten Element übereinstimmen. Andernfalls wird es mv
wörtlich übergeben. Du willst das nicht. Die Lösung besteht darin, den folgenden Befehl vorher auszuführen:
shopt -s nullglob
Mit dieser Shell-Option wird ein nicht übereinstimmender Glob zu nichts erweitert. Ich empfehle Ihnen, auch nach dotglob
Möglichkeiten zu suchen.
Beachten Sie, dass die *?foo*
Übereinstimmungen (2-3) übereinstimmen. Gleiche *foo?*
Übereinstimmung (3-4). Beachten Sie außerdem --
, mv
dass alle folgenden Argumente keine Optionen sind. Auf diese Weise wird eine Datei wie --foo
diese nicht als (unbekannte) Option interpretiert. Dies führt zu zwei besseren Befehlen:
mv -- *?foo* foo?* foo/
oder
mv -- *?foo *foo?* foo/
Es ist egal, für welchen Sie sich entscheiden. Einfach nicht verwenden mv *?foo* *foo?* foo/
; es wird (z) passieren bar-foo-baz
zu mv
zweimal (dh als zwei getrennte Argumente), wodurch ein Fehler erzeugt, wenn das Werkzeug, um dieses Objekt zum zweiten Mal zu bewegen versucht.
Wenn überhaupt keine Übereinstimmung gefunden mv
wird, degenerieren sich meine Befehle mv foo/
und werfen einen Fehler. Ihr ursprünglicher mv
Befehl (mit nullglob
unset) würde das Literal abrufen *foo*
und einen anderen Fehler auslösen.
Beispielkonsolensitzung:
$ shopt -s nullglob $ mkdir foo $ touch bar-foo bar-foo-baz foo-baz xyfooz.tex ./--foo $ mv -v -- *?foo* foo?* foo/ 'bar-foo' -> 'foo/bar-foo' 'bar-foo-baz' -> 'foo/bar-foo-baz' '--foo' -> 'foo/--foo' 'xyfooz.tex' -> 'foo/xyfooz.tex' 'foo-baz' -> 'foo/foo-baz' $
Einfacher Hack
Sagen wir dummy
mal, existiert nicht.
mv foo dummy mv *foo* dummy/ mv dummy foo
Das Umbenennen eines Verzeichnisses sollte in Inode-basierten Dateisystemen sehr schnell sein. Programme, deren Dateien bereits von innen foo/
geöffnet sind, sollten weder stören noch zerbrechen, da der Inode von Bedeutung ist. Wenn jedoch ein Programm eine Datei (einschließlich des Pfads foo/
) zwischen der ersten und der dritten Datei öffnen muss, schlägt mv
dies fehl. Andere Nebenwirkungen können auftreten (stellen Sie sich ein Drittanbieter-Programm vor, das foo/
in der Zwischenzeit neu erstellt wurde). Deshalb bezeichne ich diesen Ansatz als Hack. Überlegen Sie zweimal, bevor Sie es verwenden.
Mit find
sowieso
Dateien von Verzeichnissen zu trennen, ist eine Aufgabe für find
. Was Sie damit gemacht haben, find
ist im Grunde der richtige Weg. Was Sie (und was ich oben gemacht habe) mit mv
Shell-Globbing machen möchte, scheint… naja, "weniger richtig". Dies ist dein Befehl:
find . -maxdepth 1 -type f -name '*foo*' -exec mv {} foo \;
Dadurch find
wird mv
für jede übereinstimmende Datei ein separater Befehl ausgeführt, der gesamte Befehl wird schlecht funktionieren. Aus diesem Grund möchte man vielleicht zu einer Single wechseln mv
. Wenn dies Ihre Linie ist (und Ihre mv
und find
sind reich genug), sollten Sie diesen "sehr richtigen" Weg in Betracht ziehen:
find . -maxdepth 1 -type f -name '*foo*' -exec mv -t foo/ -- {} +
Die Vorteile gegenüber Ihrem find
Kommando und / oder einfach mv
mit glob (s):
- Ein einzelner
mv
Benutzer kann mehrere Dateien zur Bearbeitung erhalten. - Wenn jedoch zu viele Dateien für eine Befehlszeile vorhanden sind,
find
werden zusätzlichemv
Prozesse ausgeführt. - Wenn keine Datei mit dem Muster übereinstimmt,
mv
wird sie überhaupt nicht ausgeführt. - dank
--
einer Datei wie--foo
wird nicht als (unbekannte) Option interpretiertmv
;