Tại sao ls
cần một quy trình riêng để thực hiện? Tôi biết lý do tại sao các lệnh như cd
không thể được thực thi bằng cơ chế forking nhưng có bất kỳ tác hại nào nếu ls
được thực thi mà không thực hiện không?
Tại sao ls
cần một quy trình riêng để thực hiện? Tôi biết lý do tại sao các lệnh như cd
không thể được thực thi bằng cơ chế forking nhưng có bất kỳ tác hại nào nếu ls
được thực thi mà không thực hiện không?
Câu trả lời:
Câu trả lời ít nhiều ls
là một thực thi bên ngoài. Bạn có thể thấy vị trí của nó bằng cách chạy type -p ls
.
Tại sao không ls
được xây dựng vào vỏ? Vâng, tại sao nó phải như vậy? Công việc của shell không phải là bao gồm mọi lệnh có sẵn, mà là cung cấp một môi trường có khả năng chạy chúng. Một số hệ vỏ hiện đại có echo
, printf
và ilk của chúng là các khối, về mặt kỹ thuật không phải là các khối, nhưng được tạo ra vì lý do hiệu suất khi chúng được chạy liên tục (chủ yếu trong các vòng lặp chặt chẽ). Nếu không tạo ra các nội trang, trình bao sẽ phải rẽ nhánh và thực hiện một quy trình mới cho mỗi cuộc gọi đến chúng, việc này có thể cực kỳ chậm.
Ít nhất, đang chạy ls
, một thực thi bên ngoài, yêu cầu chạy một trong các nhóm thực thi của các cuộc gọi hệ thống. Bạn có thể làm điều này mà không cần gạt, nhưng nó sẽ thay thế lớp vỏ chính mà bạn đang sử dụng. Bạn có thể thấy những gì xảy ra trong trường hợp đó bằng cách làm như sau:
exec ls; echo "this never gets printed"
Vì hình ảnh quá trình của shell của bạn được thay thế, shell hiện tại không còn truy cập được sau khi thực hiện điều này. Để shell có thể tiếp tục chạy sau khi chạy ls, lệnh sẽ phải được tích hợp vào shell.
Forking cho phép thay thế một quá trình không phải là vỏ chính của bạn, điều đó có nghĩa là bạn có thể tiếp tục chạy vỏ của mình sau đó.
echo
, printf
vv
cd
không phải là một thực thi bên ngoài?
cd
thực thi trong hệ điều hành POSIX-compliant ( xem tại đây ). Tuy nhiên, nếu bạn muốn thực sự chdir () trong quy trình hiện tại, bạn cần phải tích hợp nó vào trình bao.
Các Bash Reference Manual trạng thái:
Các lệnh dựng sẵn là cần thiết để thực hiện chức năng không thể hoặc bất tiện để có được với các tiện ích riêng biệt.
Đó là, shell được thiết kế để chỉ bao gồm các lệnh tích hợp nếu:
Các ls
lệnh không phù hợp với bất kỳ của các requirments trên.
Tuy nhiên , ở đây không có ràng buộc lập trình nào có thể ngăn chặn ls
việc được cài đặt dưới dạng tích hợp, đang thực thi trong cùng một quy trình như trình thông dịch bash. Các lý do thiết kế cho các lệnh không được thực hiện dưới dạng shell dựng sẵn là:
Về lý do đầu tiên - Bạn muốn vỏ phải độc lập và đàn hồi nhất có thể. Bạn không muốn lớp vỏ bị kẹt trên giá ls
treo NFS "không phản hồi vẫn đang thử".
Về lý do thứ hai - Trong nhiều trường hợp, bạn có thể muốn sử dụng hệ vỏ cho hệ thống sử dụng Busybox hoặc hệ thống tệp khác có ls
triển khai khác . Hoặc thậm chí sử dụng cùng một nguồn shell trong các hệ điều hành có các ls
triển khai khác nhau .
Về lý do thứ ba - Đối với một biểu thức như find . -type d | xargs ls -lad
sẽ khó hoặc không thể thực hiện ls
quy trình tương tự như trình thông dịch shell.
Về lý do thứ tư - Một số ls
lệnh có thể mất nhiều thời gian để hoàn thành. Bạn có thể muốn vỏ tiếp tục làm một cái gì đó khác trong thời gian đó.
Lưu ý: Xem bài đăng hữu ích này của Warren Young để trả lời một câu hỏi tương tự.
ls
vào một quy trình bên ngoài. Nó có thể được thực hiện, nhưng nó sẽ phức tạp.
bash
đầu ra alias | grep ls
. đầu vàocat /etc/passwd | while read a; do echo "$a"; done
ls
không yêu cầu một quá trình riêng biệt. Rất ít lệnh thực sự yêu cầu một quy trình riêng: chỉ những lệnh cần thay đổi đặc quyền.
Theo quy định, shell chỉ thực hiện các lệnh dưới dạng nội trang khi các lệnh đó cần được triển khai dưới dạng nội trang. Lệnh như alias
, cd
, exit
, export
, jobs
, ... cần phải đọc hoặc sửa đổi một số trạng thái nội bộ của vỏ, và do đó không thể là các chương trình riêng biệt. Các lệnh không có yêu cầu như vậy có thể là các lệnh riêng biệt; bằng cách này, chúng có thể được gọi từ bất kỳ shell hoặc chương trình khác.
Nhìn vào danh sách các nội dung trong bash, chỉ các nội dung sau có thể được triển khai dưới dạng các lệnh riêng biệt. Đối với một số người trong số họ, sẽ có một chút mất chức năng.
command
- nhưng nó sẽ mất đi tính hữu dụng của nó trong các tình huống PATH
có thể không được thiết lập đúng và tập lệnh đang sử dụng command
như một phần của việc thiết lập nó.echo
- đó là một nội dung cho hiệu quả.help
- nó có thể sử dụng một cơ sở dữ liệu riêng biệt, nhưng việc nhúng văn bản trợ giúp vào trình thực thi shell có lợi thế là làm cho trình bao thực thi được khép kín.kill
- có hai lợi thế trong việc tích hợp sẵn: nó có thể nhận ra các chỉ định công việc ngoài ID xử lý và nó có thể được sử dụng ngay cả khi không có đủ tài nguyên để bắt đầu một quy trình riêng biệt.printf
- với cùng lý do echo
, và cũng để hỗ trợ -v
tùy chọn đặt đầu ra trong một biến.pwd
- nội dung cung cấp khả năng bổ sung của theo dõi thư mục hiện tại hợp lý (giữ nguyên các liên kết tượng trưng thay vì mở rộng chúng).test
- đó là một nội dung tích hợp cho hiệu quả (và bash cũng thực hiện một số phép thuật với các tệp được gọi /dev/fd/…
trên một số hệ điều hành).Một vài shell cung cấp một số lượng đáng kể các nội dung bổ sung. Có sash , một lớp vỏ được thiết kế thành một nhị phân độc lập để sửa chữa khẩn cấp (khi một số lệnh bên ngoài có thể không sử dụng được). Nó có tích hợp ls
, được gọi -ls
, cũng như các công cụ khác như -grep
và -tar
. Nội dung của Sash có ít khả năng hơn các lệnh chính thức. Zsh cung cấp một số nội dung tương tự trong mô-đun zsh / files . Nó không có ls
, nhưng mở rộng ký tự đại diện ( echo *
) và zstat
có thể phục vụ một chức năng tương tự.
Tôi nghĩ rằng một cái gì đó mà mọi người đang thiếu ở đây là sự phức tạp của ls
chương trình GNU trên Linux. So sánh kích thước thực thi của ls
đến bash
và dash
vỏ trên hệ thống Debian của tôi, chúng ta thấy rằng nó là khá lớn:
graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30 2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls
Bao gồm một ls
tính năng đầy đủ như phiên bản GNU trong bash
sẽ tăng kích thước thực thi lên 10%. Nó có kích thước gần giống như dash
vỏ đầy đủ !
Hầu hết các nội dung shell được chọn vì chúng tích hợp với shell theo cách mà các thực thi bên ngoài không thể (câu hỏi chỉ ra cd
, nhưng một ví dụ khác là phiên bản bash kill
tích hợp với điều khiển công việc bash) hoặc vì chúng là các lệnh rất đơn giản để thực hiện, đưa ra một tốc độ lớn so với mức chi trả kích thước ( true
và false
đơn giản như nó được).
GNU ls
đã có một chu kỳ phát triển dài và thực hiện các tùy chọn có thể tùy chỉnh những gì / cách hiển thị kết quả. Sử dụng một ls theo mặc định sẽ làm mất chức năng này hoặc làm tăng đáng kể độ phức tạp và kích thước của vỏ.
Điều này làm những gì bạn đang tìm kiếm:
printf "%s\n" *
Ngoài ra, bạn có thể lưu trữ tên tệp trong mảng:
files=(`printf "%s\n" *`) #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done
Nhưng nó không quan tâm đến khoảng trắng trong tên
Điều này chuyển sang biến và quan tâm đến khoảng trắng:
printf "%s\n" * | while read a; do echo $a; done
ls
là một chương trình bên ngoài,echo *
hoặcecho * .*
(tùy thuộc vào các tùy chọn shell) thực hiện khá tốt việc liệt kê các tệp mà không cần chuyển.