In einem Skript, wenn ich #!/bin/bash
einfüge oben, das wird gut funktionieren:
cp directory/{foo,bar} destination
Bei sh gibt dies jedoch den Fehler „keine solche Datei oder kein solches Verzeichnis“ aus. Gibt es in sh eine andere Möglichkeit, dasselbe Endziel mit einem Befehl zu erreichen?
Akzeptierte Antwort:
Wie Sie bemerkt haben, unterstützen nicht alle Shells die Klammererweiterung.
Weg 1:Zwei getrennte Pfade (d. h. Präfix zweimal schreiben)
Wenn Ihr Ziel wirklich nur darin besteht, dies in einem Befehl zu tun, gibt es einen einfachen Weg:
cp directory/file1 directory/file2 destination
Der cp
Der Befehl unterstützt mehrere Quellargumente gefolgt von einem Zielargument. Genau das passiert mit dem Befehl, der für Sie in Bash funktioniert. Bash führt eine Klammererweiterung durch, die den von Ihnen verwendeten Befehl in den oben gezeigten konvertiert. Das heißt, wenn Sie cp directory/{file1,file2} destination
ausführen in Bash das cp
Befehl sieht niemals geschweifte Klammern.
Ein solcher Befehl ist einfach und leicht zu verstehen. Ich schlage vor, darüber nachzudenken.
Weg 2:Eine Variable für das Präfix
Aber wenn Ihr Ziel darin besteht, eine Wiederholung zu vermeiden selbst, dann möchten Sie es vielleicht lieber nicht so machen, besonders wenn directory
ist eigentlich ein langer Weg. Wenn Sie den Pfad später im Skript bearbeiten müssen, müssen Sie schließlich Änderungen an beiden Vorkommen vornehmen.
Sie können directory
speichern (oder was auch immer, vermutlich längerer Pfad) in einer Shell-Variablen:
dir='directory'
cp "$dir/file1" "$dir/file2" destination
$dir
ist Parametererweiterung. Die Shell ersetzt ihn durch den Wert, der in der Variablen dir
enthalten ist . Wenn Sie die Parametererweiterung verwenden, sollten Sie nicht weglassen die doppelten Anführungszeichen – außer in dem seltenen Fall, dass Feldaufteilung und Globbing durchgeführt werden sollen. (Dies gilt auch für Bash.)
Das sind zwei Befehle, aber wenn Ihr eigentliches Ziel darin besteht, sich nicht zu wiederholen, ist das vielleicht das, was Sie wollen. Sie könnten schreiben
dir='directory'; cp "$dir/file1" "$dir/file2" destination
um es zu „einem Befehl“ zu machen, aber das ist nicht kürzer und etwas weniger lesbar.
(Beachten Sie, dass Sie ;
nicht einfach entfernen können dort. Das Ergebnis wäre ein wohlgeformter Befehl, aber er würde nicht das tun, was Sie wollen. Es würde cp
ausführen Befehl, der eine Umgebungsvariable namens dir
übergibt mit dem Wert directory
in den cp
Umgebung des Kommandos. Da es die Schale ist und nicht das cp
Befehl, der dir
erweitert , das würde nicht funktionieren.)
Weg 3:cd
ig zum Präfix
Wenn Ihr Skript nach Ausführung dieser Operation nichts weiter tut oder es für nachfolgende Befehle keine Rolle spielt, wie das aktuelle Verzeichnis lautet, dann if destination
ist ein absoluter Pfad , können Sie Folgendes verwenden:
cd directory
cp file1 file2 destination
Ich empfehle dies jedoch nicht für das Skripting, es sei denn, Ihr Skript führt nachfolgende Aktionen aus, die von der Ausführung aus diesem Verzeichnis profitieren, oder es kann knapper oder einfacher geschrieben werden, wenn es von diesem Verzeichnis aus ausgeführt wird. Außer wenn das Verzeichnis, aus dem ein Skript ausgeführt wird, sinnvoll ist für den Zweck des Skripts, kann es schwieriger werden, über das Skript nachzudenken, wenn man sich darauf verlässt; außerdem, wenn die cd
Befehl erfolgreich, aber der cp
Befehl fehlschlägt, sind die resultierenden Fehlermeldungen möglicherweise nicht ganz aufschlussreich. Stattdessen erwähne ich die Technik von cd
ing in das Quellverzeichnis, weil es ein nützliches Muster für interaktiv ist Shell-Verwendung.
(Wie Hannu betonte, können Sie eine beliebige Anzahl von Befehlen zusammen innerhalb von (
)
um sie in einer Subshell auszuführen, und Änderungen an der Shell-Umgebung, einschließlich der Wirkung von cd
, wird nicht bestehen bleiben, nachdem der Befehl ausgeführt wurde. Dies ist eine weithin nützliche Technik, und es war eine wesentliche Unterlassung, dass ich sie nicht erwähnt hatte. Beachten Sie jedoch, dass dies keine Probleme im Zusammenhang mit einem relativen Pfad für destination
mindert .)
Beachten Sie, dass wenn cd
Wenn der Befehl fehlschlägt, werden die anderen Befehle normalerweise trotzdem ausgeführt. Dies könnte verschiedene Dateien kopieren, die Sie nicht kopieren möchten (wenn es andere Dateien mit denselben Namen in dem Verzeichnis gibt, aus dem das Skript ausgeführt wurde) oder verwirrende Fehlermeldungen erzeugen. Vielleicht bevorzugen Sie also:
cd directory && cp file1 file2 destination
Der &&
bewirkt, dass der zweite Befehl nur ausgeführt wird, wenn der erste Befehl erfolgreich war. Beachten Sie, dass dies den Effekt der Ausführung des ersten Befehls immer noch nicht rückgängig macht. Nachdem das Ganze gelaufen ist, befinden Sie sich immer noch im directory
, es sei denn, Sie haben es in einer Subshell mit (
)
.