Bash-Klammer-Erweiterung nach einem Pfad-Schrägstrich

12

Ich versuche, eine Datei mit geschweiften Klammern unter einem anderen Namen in dasselbe Verzeichnis zu kopieren. Ich benutze Bash 4.4.18.

Folgendes habe ich getan:

cp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}

aber ich bekomme diesen fehler:

cp: cannot stat '/home/xyz/some/dir/{my-file-to-rename.bin,': No such file or directory

Sogar eine einfache Klammererweiterung wie diese gibt mir den gleichen Fehler:

cp {my-file-to-rename.bin, new-name-of-file.bin}

Was mache ich falsch?

nanangarsyad
quelle

Antworten:

29

Die Klammererweiterungssyntax akzeptiert Kommas, jedoch kein Leerzeichen nach dem Komma. In vielen Programmiersprachen sind Leerzeichen nach Kommas an der Tagesordnung, hier jedoch nicht. In Bash verhindert das Vorhandensein eines Leerzeichens ohne Anführungszeichen, dass eine Klammererweiterung durchgeführt wird.

Entfernen Sie das Leerzeichen, und es wird funktionieren:

cp ~/some/dir/{my-file-to-rename.bin,new-name-of-file.bin}

Beachten Sie, dass Sie das Nachziehen .binaußerhalb der geschweiften Klammern verschieben können, obwohl dies überhaupt nicht erforderlich ist :

cp ~/some/dir/{my-file-to-rename,new-name-of-file}.bin

Wenn Sie den Effekt der Klammererweiterung testen möchten, können Sie dies mit echooder printf '%s 'oder printfmit einer beliebigen Formatzeichenfolge tun. (Ich persönlich benutze echodies nur, wenn ich mich in Bash befinde , da Bashs echoeingebaute Escape-Sequenzen standardmäßig nicht erweitern und daher ziemlich gut geeignet ist, um zu überprüfen, welcher Befehl tatsächlich ausgeführt wird.) Zum Beispiel:

ek@Io:~$ echo cp ~/some/dir/{my-file-to-rename,new-name-of-file}.bin
cp /home/ek/some/dir/my-file-to-rename.bin /home/ek/some/dir/new-name-of-file.bin
Eliah Kagan
quelle
23

string{foo, bar}ist keine Klammererweiterung; es sind die zwei Wörter string{foo,und bar}. Um die Klammererweiterung zu verwenden, müssen sich die Klammern im selben Wort befinden. Sie müssen entweder den zusätzlichen Speicherplatz entfernen, wenn Sie ihn nicht benötigen, oder ihn zitieren, wenn Sie ihn benötigen:

$ printf "%s\n" aa{bb, cc}
aa{bb,
cc}
$ printf "%s\n" aa{bb,cc}
aabb
aacc
$ printf "%s\n" aa{bb," cc"}
aabb
aa cc
ilkkachu
quelle
+1 für das klare Beispiel und danke. Ich gebe meine Zustimmung, wenn mein Ruf ausreicht. :)
Nanangarsyad
Es gibt noch etwas, das über "Muschelwörter" erwähnt werden sollte. . .wie weiß Shell, wo Wörter zu
trennen
-1

Bash behandelt diesen Raum wie jeden anderen. B. IFS, The Internal Field Separator. Dies wird zum Teilen von Wörtern nach der Erweiterung und zum Teilen von Zeilen in Wörter mit dem Befehl read builtin verwendet.

Die Shell behandelt jedes IFS-Zeichen als Trennzeichen und teilt die Ergebnisse der anderen Erweiterungen in Wörter für diese Zeichen auf. Wenn IFS nicht gesetzt ist oder sein Wert genau der Standardwert ist, werden die Folgen von und am Anfang und Ende der Ergebnisse der vorherigen Erweiterungen ignoriert und jede Folge von IFS-Zeichen, die nicht am Anfang oder Ende steht, dient zur Begrenzung Wörter. Wenn IFS einen anderen Wert als den Standardwert hat, werden Sequenzen des Leerzeichens und des Tabulators am Anfang und Ende des Wortes ignoriert, solange sich das Leerzeichen im Wert von IFS (einem IFS-Leerzeichen) befindet. Jedes Zeichen in IFS, das kein IFS-Whitespace ist, begrenzt zusammen mit benachbarten IFS-Whitespace-Zeichen ein Feld. Eine Folge von IFS-Whitespace-Zeichen wird ebenfalls als Begrenzer behandelt. Wenn der Wert von IFS null ist,
-bash (1)

Durch Einfügen des Trennzeichens ohne Flucht haben Sie bash mitgeteilt, dass Ihr Befehl und Ihre Argumente wie folgt lauten:

  1. "cp"
  2. "~ / some / dir / {my-file-to-rename.bin,"
  3. "neuer-name-der-datei.bin}"

Hätten Sie Anführungszeichen oder eine Flucht "\", hätten Sie:

  1. "cp"
  2. "~ / some / dir / {meine-datei-umbenennen.bin, \ neuer-name-der-datei.bin}"

Das wäre auch nicht das, was Sie wollten, es sei denn, "new-name-of-file.bin" ist der neue Dateiname, den Sie wollten. Platz inbegriffen. Wenn zuerst die geschweifte Klammer und dann die Tilde-Erweiterung erfolgt, führt bash Folgendes aus:

  1. "cp"
  2. "/path/to/home/some/dir/my-file-to-rename.bin"
  3. "/ path / to / home / some / dir / \ neuer-name-der-datei.bin"

Das Entfernen des Leerzeichens würde all das beheben.

cde
quelle
5
Das ist meistens gut, aber Sie scheinen zu sagen, dass Worttrennung passiert cp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}und IFSdas Ergebnis beeinflusst. Weder ist so. Hier ist Leerzeichen ein Metazeichen bei der Tokenisierung ( Schritt 2 ). Siehe 3.5.7 über das Aufteilen. Versuchen Sie es IFS=xdann printf '[%s]\n' {a,b} printf '[%s]\n' {a, b} printf '[%s]\n' {a,xb} printf '[%s]\n' {a, xb}.
Eliah Kagan