Khi bạn chạy lệnh này:
ls
thiết bị đầu cuối hiển thị đầu ra của ls
.
Khi bạn chạy lệnh này:
echo $(ls)
Shell nắm bắt đầu ra $(ls)
và thực hiện phân tách từ trên nó. Với mặc định IFS
, điều này có nghĩa là tất cả các chuỗi khoảng trắng, bao gồm các ký tự dòng mới, được thay thế bằng một khoảng trống. Đó là lý do tại sao đầu ra echo $(ls)
xuất hiện trên một dòng.
Để thảo luận nâng cao về phân tách từ, hãy xem Câu hỏi thường gặp của Greg .
Ngăn chặn chia tách từ
Shell không thực hiện phân tách từ trên chuỗi trong dấu ngoặc kép. Do đó, bạn có thể ngăn chặn việc tách từ và giữ lại đầu ra đa dòng bằng:
echo "$(ls)"
ls
và sản lượng đa dòng
Bạn có thể nhận thấy rằng ls
đôi khi in nhiều hơn một tệp trên mỗi dòng:
$ ls
file1 file2 file3 file4 file5 file6
Đây là mặc định khi đầu ra của ls
đi đến một thiết bị đầu cuối. Khi đầu ra không trực tiếp đến thiết bị đầu cuối, ls
thay đổi mặc định của nó thành một tệp trên mỗi dòng:
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
Hành vi này được ghi lại trong man ls
.
Một sự tinh tế khác: thay thế lệnh và các dòng mới
$(...)
là sự thay thế lệnh và shell sẽ loại bỏ các ký tự dòng mới khỏi đầu ra của sự thay thế lệnh . Điều này thường không đáng chú ý vì theo mặc định, echo
thêm một dòng mới vào cuối đầu ra của nó. Vì vậy, nếu bạn mất một dòng mới từ cuối $(...)
và bạn có được một dòng từ echo
đó, không có thay đổi. Tuy nhiên, nếu đầu ra của lệnh của bạn kết thúc bằng 2 hoặc nhiều ký tự dòng mới trong khi chỉ echo
thêm lại một ký tự , thì đầu ra của bạn sẽ thiếu một hoặc nhiều dòng mới. Ví dụ, chúng ta có thể sử dụng printf
để tạo các ký tự dòng mới. Lưu ý rằng cả hai lệnh sau, mặc dù có số dòng mới khác nhau, tạo ra cùng một đầu ra của một dòng trống:
$ echo "$(printf "\n")"
$ echo "$(printf "\n\n\n\n\n")"
$
Hành vi này được ghi lại trongman bash
.
Một điều ngạc nhiên khác: mở rộng tên đường dẫn, hai lần
Hãy tạo ba tệp:
$ touch 'file?' file1 file2
Quan sát sự khác biệt giữa ls file?
và echo $(ls file?)
:
$ ls file?
file? file1 file2
$ echo $(ls file?)
file? file1 file2 file1 file2
Trong trường hợp echo $(ls file?)
, tệp toàn cầu file?
được mở rộng hai lần , khiến tên tệp file1
và file2
xuất hiện hai lần trong đầu ra. Điều này là do, như Jeffiekins chỉ ra, việc mở rộng tên đường dẫn được thực hiện trước tiên bởi trình bao trước khi ls
được chạy và sau đó lại thực hiện trướcecho
được chạy.
Việc mở rộng tên đường dẫn thứ hai có thể bị chặn nếu chúng ta sử dụng dấu ngoặc kép:
$ echo "$(ls file?)"
file?
file1
file2