Espansione del tutore dopo un taglio del percorso


12

Sto cercando di copiare un file con un nome diverso nella stessa directory usando l'espansione del controvento. Sto usando bash 4.4.18.

Ecco cosa ho fatto:

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

ma ottengo questo errore:

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

Anche una semplice espansione di parentesi come questa mi dà lo stesso errore:

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

Che cosa sto facendo di sbagliato?

Risposte:


29

La sintassi di espansione del controvento accetta le virgole, ma non accetta uno spazio dopo la virgola. In molti linguaggi di programmazione, gli spazi dopo le virgole sono all'ordine del giorno, ma non qui. In Bash, la presenza di uno spazio non quotato impedisce l'espansione del controvento.

Rimuovi lo spazio e funzionerà:

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

Sebbene non sia affatto necessario, si noti che è possibile spostare il trascinamento .binall'esterno delle parentesi graffe:

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

Se vuoi testare l'effetto dell'espansione del controvento, puoi usare echoo printf '%s ', o printfcon qualsiasi stringa di formato preferisci, farlo. (Personalmente lo uso solo echoper questo, quando sono in Bash, perché l' echointegrato di Bash non espande le sequenze di escape per impostazione predefinita, ed è quindi ragionevolmente adatto a controllare quale comando verrà effettivamente eseguito.) Ad esempio:

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

23

string{foo, bar}non è espansione di parentesi graffe; sono le due parole string{foo,e bar}. Per usare l'espansione delle parentesi graffe, le parentesi graffe devono essere all'interno della stessa parola. Dovrai rimuovere lo spazio extra se non ne hai bisogno, o citarlo se ne hai bisogno:

$ 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

+1 per l'esempio chiaro e grazie. Darò il mio voto quando la mia reputazione sarà sufficiente. :)
nanangarsyad

C'è qualcos'altro che dovrebbe essere menzionato sulle "parole shell". . .come fa Shell a sapere dove dividere le parole;)
Sergiy Kolodyazhnyy

-1

Bash tratta quello spazio come farebbe qualsiasi altro. Come IFS, il separatore di campo interno. Questo è usato per la divisione delle parole dopo l'espansione e per dividere le linee in parole con il comando read incorporato.

La shell tratta ogni carattere di IFS come un delimitatore e divide i risultati delle altre espansioni in parole su questi caratteri. Se IFS non è impostato o il suo valore è esattamente, l'impostazione predefinita, quindi le sequenze di, e all'inizio e alla fine dei risultati delle espansioni precedenti vengono ignorate e qualsiasi sequenza di caratteri IFS non all'inizio o alla fine serve a delimitare parole. Se IFS ha un valore diverso da quello predefinito, le sequenze dello spazio e della scheda degli spazi bianchi vengono ignorate all'inizio e alla fine della parola, purché il carattere degli spazi bianchi sia nel valore di IFS (un carattere degli spazi bianchi IFS). Qualsiasi carattere in IFS che non sia uno spazio bianco IFS, insieme a qualsiasi carattere di spazio bianco IFS adiacente, delimita un campo. Una sequenza di caratteri spazi bianchi IFS viene anche trattata come delimitatore. Se il valore di IFS è null,
-bash (1)

Inserendo il delimitatore, senza caratteri di escape, hai detto a bash che il tuo comando e gli argomenti sono:

  1. "Cp"
  2. "~ / Some / dir / {my-file-to-rename.bin,"
  3. "New-nome-di-file.bin}"

Se avessi avuto virgolette o una fuga "\", avresti:

  1. "Cp"
  2. "~ / some / dir / {my-file-to-rename.bin, \ new-name-of-file.bin}"

Che non sarebbe anche quello che volevi, a meno che "new-name-of-file.bin" sia il nuovo nome file che volevi. Spazio incluso Appena si verifica l'espansione del controvento, quindi l'espansione della tilde, bash esegue:

  1. "Cp"
  2. "/Path/to/home/some/dir/my-file-to-rename.bin"
  3. "/ path / to / home / some / dir / \ new-name-of-file.bin"

Basta rimuovere lo spazio per risolvere tutto ciò.


5
Questo è per lo più buono, ma lei sembra dire suddivisione delle parole accade sul cp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}e IFSinfluenza il risultato. Nemmeno è così. Qui, lo spazio è un metacarattere nella tokenizzazione ( passaggio 2 ). Vedere 3.5.7 su quando si verifica la divisione. Prova IFS=xallora printf '[%s]\n' {a,b} printf '[%s]\n' {a, b} printf '[%s]\n' {a,xb} printf '[%s]\n' {a, xb}.
Eliah Kagan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.