Rozwinięcie nawiasu klamrowego po ukośniku ścieżki


12

Próbuję skopiować plik pod inną nazwą do tego samego katalogu, używając rozszerzenia nawiasów klamrowych. Używam bash 4.4.18.

Oto co zrobiłem:

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

ale pojawia się ten błąd:

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

Nawet takie proste rozwinięcie nawiasu klamrowego daje mi ten sam błąd:

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

Co ja robię źle?

Odpowiedzi:


29

Ekspansja klamra składnia akceptuje przecinków, ale nie akceptuje miejsca po przecinku. W wielu językach programowania spacje po przecinkach są powszechne, ale nie tutaj. W Bash obecność niecytowanej przestrzeni uniemożliwia wykonanie rozwinięcia nawiasu.

Usuń spację, a to zadziała:

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

Chociaż wcale nie jest to wymagane, pamiętaj, że możesz przesunąć spływ .binpoza klamry:

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

Jeśli chcesz przetestować działanie interpretacji nawiasów, można użyć echoalbo printf '%s ', albo printfz dowolnym formacie ciąg wolisz, aby to zrobić. (Osobiście używam echodo tego, gdy jestem w Bash, ponieważ wbudowane Bashecho domyślnie nie rozwija sekwencji ucieczki, a zatem jest całkiem odpowiednie do sprawdzania, które polecenie faktycznie uruchomi się.) Na przykład:

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}nie jest rozszerzaniem nawiasów klamrowych; to dwa słowa string{foo,i bar}. Aby użyć rozwinięcia nawiasów, nawiasy klamrowe muszą znajdować się w tym samym słowie. Będziesz musiał usunąć dodatkowe miejsce, jeśli go nie potrzebujesz, lub podać je, jeśli potrzebujesz:

$ 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 za wyraźny przykład i dziękuję. Oddam głos, gdy moja reputacja będzie wystarczająca. :)
nanangarsyad

Jest coś jeszcze, co należy wspomnieć o „słowach powłoki”. . .jak skąd muszla wie, gdzie dzielić słowa;)
Sergiy Kolodyazhnyy

-1

Bash traktuje tę przestrzeń tak, jak każdą inną. Jak IFS, separator pola wewnętrznego. Służy do dzielenia słów po rozwinięciu i dzielenia linii na słowa za pomocą wbudowanego polecenia odczytu.

Powłoka traktuje każdy znak IFS jako ogranicznik i dzieli wyniki pozostałych rozszerzeń na słowa na te znaki. Jeśli IFS jest rozbrojony lub jego wartość jest dokładnie domyślna, wówczas sekwencje, oraz na początku i na końcu wyników poprzednich rozszerzeń są ignorowane, a dowolna sekwencja znaków IFS nie na początku ani na końcu służy do rozgraniczenia słowa. Jeśli IFS ma wartość inną niż domyślna, to sekwencje spacji i tabulacji białych znaków są ignorowane na początku i na końcu słowa, o ile znak spacji ma wartość IFS (biały znak IFS). Każdy znak w IFS, który nie jest białą spacją IFS, wraz z dowolnymi sąsiadującymi znakami białych spacji IFS, ogranicza pole. Sekwencja białych znaków IFS jest również traktowana jako separator. Jeśli wartość IFS jest null,
-bash (1)

Wstawiając separator, nieskalowany, powiedziałeś bashowi, że twoje polecenie i argumenty to:

  1. „cp”
  2. „~ / some / dir / {my-file-to-rename.bin,”
  3. „new-name-of-file.bin}”

Gdybyś miał cytaty lub znak ucieczki „\”, miałbyś:

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

Co również nie byłoby tym, czego chciałeś, chyba że „new-name-of-file.bin” jest nową nazwą pliku, którą chciałeś. Miejsce w komplecie. Ponieważ najpierw następuje rozwinięcie nawiasu, a następnie rozszerzenie tyldy, bash wykona:

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

Usunięcie tego miejsca naprawiłoby to wszystko.


5
Jest to w większości dobre, ale wydaje się, że dzielenie słów ma miejsce cp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}i IFSwpływa na wynik. Tak też nie jest. Tutaj spacja jest metaznakiem w tokenizacji ( krok 2 ). Zobacz rozdział 3.5.7, kiedy nastąpi podział. Spróbuj IFS=xwięc printf '[%s]\n' {a,b} printf '[%s]\n' {a, b} printf '[%s]\n' {a,xb} printf '[%s]\n' {a, xb}.
Eliah Kagan,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.