Bash mở rộng cú đúp sau một dấu gạch chéo


12

Tôi đang cố sao chép một tập tin sang một tên khác vào cùng một thư mục bằng cách sử dụng mở rộng dấu ngoặc. Tôi đang sử dụng bash 4.4.18.

Đây là những gì tôi đã làm:

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

nhưng tôi gặp lỗi này:

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

Ngay cả một mở rộng cú đúp đơn giản như thế này cũng gây ra lỗi tương tự:

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

Tôi đang làm gì sai?

Câu trả lời:


29

Các mở rộng cú đúp cú pháp chấp nhận dấu phẩy, nhưng nó không chấp nhận một không gian sau dấu phẩy. Trong nhiều ngôn ngữ lập trình, không gian sau dấu phẩy là phổ biến, nhưng không phải ở đây. Ở Bash, sự hiện diện của một không gian không trích dẫn ngăn cản việc mở rộng niềng răng được thực hiện.

Xóa không gian và nó sẽ hoạt động:

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

Mặc dù hoàn toàn không cần thiết, lưu ý rằng bạn có thể di chuyển dấu vết .binbên ngoài niềng răng:

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

Nếu bạn muốn kiểm tra hiệu quả của việc mở rộng niềng răng, bạn có thể sử dụng echohoặc printf '%s ', hoặc printfvới bất kỳ chuỗi định dạng nào bạn thích, để làm điều đó. (Cá nhân tôi chỉ sử dụng echocho việc này, khi tôi ở Bash, bởi vì nội dung của Bashecho không mở rộng các chuỗi thoát theo mặc định, và do đó rất phù hợp để kiểm tra lệnh nào sẽ thực sự chạy.) Ví dụ:

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}không phải là mở rộng cú đúp; đó là hai từ string{foo,bar} . Để sử dụng mở rộng niềng răng, niềng răng cần phải nằm trong cùng một từ. Bạn sẽ phải xóa thêm dung lượng nếu bạn không cần hoặc trích dẫn nếu bạn cần:

$ 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 cho ví dụ rõ ràng và cảm ơn bạn. Tôi sẽ cung cấp cho tôi khi danh tiếng của tôi là đủ. :)
nanangarsyad

Có một cái gì đó khác cần được đề cập về "từ vỏ". . .như làm sao vỏ biết cách chia từ;)
Sergiy Kolodyazhnyy

-1

Bash đối xử với không gian như bất kỳ nơi nào khác. Như IFS, Dấu tách trường nội bộ. Điều này được sử dụng để phân tách từ sau khi mở rộng và để phân chia các dòng thành các từ bằng lệnh đọc dựng sẵn.

Shell xử lý từng ký tự của IFS như một dấu phân cách và chia kết quả của các bản mở rộng khác thành các từ trên các ký tự này. Nếu IFS không được đặt hoặc giá trị của nó là chính xác, mặc định, sau đó các chuỗi, và ở đầu và cuối kết quả của các lần mở rộng trước đó sẽ bị bỏ qua và bất kỳ chuỗi ký tự IFS nào không ở đầu hoặc cuối đều phân định từ ngữ. Nếu IFS có một giá trị khác với mặc định, thì các chuỗi không gian và tab ký tự khoảng trắng sẽ bị bỏ qua ở đầu và cuối của từ, miễn là ký tự khoảng trắng nằm trong giá trị của IFS (ký tự khoảng trắng IFS). Bất kỳ ký tự nào trong IFS không phải là khoảng trắng IFS, cùng với bất kỳ ký tự khoảng trắng IFS liền kề nào, sẽ phân định một trường. Một chuỗi các ký tự khoảng trắng IFS cũng được coi là một dấu phân cách. Nếu giá trị của IFS là null,
-bash (1)

Bằng cách chèn dấu phân cách, không thoát, sau đó bạn nói với bash lệnh của bạn và các đối số là:

  1. "cp"
  2. "~ / some / dir / {my-file-to-rename.bin,"
  3. "tên mới của tập tin.bin}"

Nếu bạn có dấu ngoặc kép hoặc thoát "\", bạn sẽ có:

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

Đó cũng sẽ không phải là những gì bạn muốn, trừ khi "tên mới của tệp.bin" là tên tệp mới bạn muốn. Không gian bao gồm. Khi mở rộng cú đúp xảy ra trước, và sau đó là mở rộng dấu ngã, bash sẽ thực thi:

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

Chỉ cần loại bỏ không gian sẽ khắc phục tất cả điều đó.


5
Điều này chủ yếu là tốt, nhưng bạn dường như nói rằng việc chia tách từ xảy ra cp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}IFSảnh hưởng đến kết quả. Cũng không phải vậy. Ở đây, không gian là một metacharacter trong mã thông báo ( bước 2 ). Xem 3.5.7 khi chia tách xảy ra. Hãy thử IFS=xsau đó printf '[%s]\n' {a,b} printf '[%s]\n' {a, b} printf '[%s]\n' {a,xb} printf '[%s]\n' {a, xb}.
Eliah Kagan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.