Liệt kê các phần tử có khoảng trắng trong zsh


10

Tôi đã nghiên cứu kịch bản zsh trong suốt 2 giờ tại thời điểm này và tôi đã va vào tường. Tôi muốn đi qua một danh sách các tập tin có thể có không gian trong đó. Tôi mở cho các cách tiếp cận hoàn toàn khác với ví dụ sau miễn là chúng là zsh vì zsh là thứ tôi đang học, không phải là nhiệm vụ tôi đang cố gắng viết kịch bản.

files=(`ls`)
for f in $files; do
    print $f
done

Tôi rõ ràng không chỉ tái tạo ls, tôi chỉ muốn $fchụp toàn bộ tên tệp mỗi lần lặp của vòng lặp.

Câu trả lời:


12

Đầu tiên, tôi cho rằng việc sử dụng lschỉ là một ví dụ. Bạn không thể phân tích đầu ra của lsbất kỳ shell nào, vì nó không rõ ràng. Đọc tại sao bạn không nên phân tích đầu ra của ls (1) nếu đây là tin tức với bạn. Trong bất kỳ shell nào, để có được danh sách các tệp, hãy sử dụng ký tự đại diện, vd files=(*).

Trong zsh, giống như trong các shell khác, kết quả của việc thay thế lệnh được chia thành các từ ở các ký tự khoảng trắng (chính xác hơn, theo giá trị của IFS). (Không giống như các shell khác, kết quả của việc thay thế lệnh không phải là đối tượng toàn cầu trong zsh.) Vì vậy, nếu đầu ra của lslệnh là

hello world
wibble

sau đó files=($(ls))đặt filesmảng để chứa 3 yếu tố: hello, worldwibble.

Nếu thay thế lệnh là trong dấu ngoặc kép, thì không có sự phân tách nào được thực hiện. Bạn có thể thực hiện phân tách tùy chỉnh với cờ mở rộng tham số . Sử dụng @cờ để chỉ ra rằng kết quả của việc phân tách là một mảng (kỳ lạ, bạn cần giữ sự mở rộng trong dấu ngoặc kép, nghĩa là "${(@)…}", mặc dù chuỗi trích dẫn kép sẽ mở rộng thành nhiều từ). Để phân tách, sử dụng scờ, ví dụ "${(@s:,:)…}"để phân tách tại dấu phẩy; các flá cờ chia tách chỉ dòng mới.

files=("${(@f)$(ls)}")

Lưu ý rằng cách thích hợp để lặp lại trên một mảng nói chung là for f in $files[@], $filesloại bỏ các phần tử trống (ở đây, điều đó không quan trọng vì các phần tử sẽ không trống).

print $fdiễn giải $fnhư một công tắc nếu nó bắt đầu bằng một -và mở rộng dấu gạch chéo ngược trong $f. Sử dụng print -r -- $fhoặc print -rn -- $fnếu bạn không muốn thêm một dòng mới sau chuỗi.


Cảm ơn bạn. Vâng, tôi chỉ là một ví dụ. Hiện tại không có mục tiêu cụ thể nào trong đầu, tôi chỉ muốn biết cách trích dẫn hoặc thoát khỏi các thành phần danh sách khỏi bất kỳ lệnh nào có thể có kết quả riêng lẻ với khoảng trắng trong đó.
Felix

Một điều mà tôi thấy khó hiểu là tại sao biểu thức ngoài () trong tệp của bạn = ("$ {(@ f) $ (ls)}") là cần thiết với @f? Và chỉ chơi xung quanh (f) dường như hoạt động tốt miễn là () xuất hiện ở bên ngoài.
Koobz

@Koobz 1. Bên ngoài (…)là cần thiết để đó fileslà một mảng chứ không phải là một chuỗi (sẽ chứa nối các dòng từ lệnh, hoàn tác việc phân tách được thực hiện bởi (f)). 2. Với foo=$'one\n\nthree', contrast bản in -rl $ {(f) foo} `và print "${(@f)foo}". Dấu ngoặc kép là cần thiết để giữ lại các dòng trống, mà bạn sẽ không nhận được lsnhưng có thể xảy ra với các lệnh khác.
Gilles 'SO- ngừng trở nên xấu xa'

Nhiều đánh giá cao. Có bất kỳ vần điệu hoặc lý do cho sự điên rồ này? Ngay cả ở đó, điều khó hiểu là tại sao bên ngoài () không phân tách lại chuỗi trên các từ riêng lẻ nếu giá trị trung gian là chuỗi nối của tôi. Điều này trông giống như nội suy chuỗi trong ruby ​​hoặc php chẳng hạn.
Koobz

@Koobz Lý do cho việc xử lý đặc biệt các từ trống là khả năng tương thích lịch sử với các phiên bản cũ hơn đã bị lãng quên của zsh. Lý do không tự động chia tách là vì đó là một hành vi đáng ngạc nhiên và thường không mong muốn. Tự động tách là một hành vi của vỏ Bourne mà zsh không mô phỏng trừ khi bạn nói với nó.
Gilles 'SO- ngừng trở nên xấu xa'

2

Trong zsh, bạn có thể sử dụng phần mở rộng của shell không thực hiện phân tách từ theo mặc định. Thử

for f in /path/to/files/*; do
    print ${f}
done
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.