Tại sao, lsv đòi hỏi một quy trình riêng để thực hiện?


14

Tại sao lscầ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ư cdkhô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?


1
Mặc dù lslà một chương trình bên ngoài, echo *hoặc echo * .*(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.
gerrit

Điều này thậm chí còn tốt hơn: printf "% s \ n" *
Costa

Shell đa dạng lưu ý: tcsh có một nội dung ls-Fhoạt động như thế nào ls -F. Đó là hiệu quả. Bạn luôn luôn nhận được -Fmà thường là một ý tưởng tốt. Nếu bạn chỉ định bất kỳ tùy chọn nào khác, nó sẽ chuyển sang lệnh bên ngoài.

Câu trả lời:


18

Câu trả lời ít nhiều lslà 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, printfvà 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 đó.


1
Tôi nghĩ rằng anh ta đang hỏi tại sao ls (1) không phải là tính năng dựng sẵn của shell, mà ai đó sẽ cần giải thích cách các nhà cung cấp khác nhau có các tùy chọn khác nhau cho ls (1) và có thể truy vấn các nội dung khác nhau từ hệ thống tệp, v.v. những thăng trầm, và chủ yếu là những nhược điểm của việc nó được 'xây dựng' vỏ.
llua

@llua tôi đã thêm một số thông tin về điều đó, và các trường hợp ngoại lệ của echo, printfvv
Chris Xuống

Không phải lúc nào cũng rõ ràng tại sao một số thứ là nội dung và những thứ khác thì không. Ví dụ, tại sao cdkhông phải là một thực thi bên ngoài?
Faheem Mitha

@FaheemMitha Có một bên ngoài cdthự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.
Chris Down

nó đã trở thành một thói quen tại sao lslà bên ngoài, nhưng nó cũng có thể được thực hiện trong một cái vỏ. Xem bận rộn.

15

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:

  1. Yêu cầu theo tiêu chuẩn POSIX
  2. Các lệnh yêu cầu quyền truy cập vào chính shell, chẳng hạn như tích hợp kiểm soát công việc
  3. Các lệnh rất đơn giản, không phụ thuộc hệ điều hành và tăng hiệu quả thực thi khi được triển khai dưới dạng dựng sẵn, chẳng hạn như printf

Các lslệ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 lsviệ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à:

  1. Shell phải tách biệt với hệ thống tập tin - không có lệnh tích hợp nào phụ thuộc vào hoạt động chính xác của bất kỳ hệ thống tập tin hoặc thiết bị ngoại vi nào
  2. Một lệnh có thể là loại hệ thống tập tin hoặc phụ thuộc hệ điều hành phải là một tệp thực thi riêng
  3. Một lệnh mà bạn có thể muốn chuyển đến hoặc từ phải là một quá trình riêng biệt
  4. Một lệnh mà bạn có thể muốn chạy trong nền phải là một tệp thực thi riêng
  5. Một lệnh có số lượng lớn các tham số có thể được thực hiện tốt hơn trong một tệp thực thi riêng
  6. Các lệnh nên có cùng một đầu ra, bất kể loại shell nào (bash, csh, tsh, ...) đều gọi chúng nên là các tệp thực thi độc lập

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á lstreo 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ó lstriể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 lstriể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 -ladsẽ khó hoặc không thể thực hiện lsquy trình tương tự như trình thông dịch shell.

Về lý do thứ tư - Một số lslệ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ự.


Bạn đã bỏ lỡ sự dễ dàng của đầu ra đường ống nếu đó là một lệnh riêng biệt và tất cả các chương trình mà nó sẽ thực hiện để chuyển một lớp vỏ nguyên thủy thành một tệp thực thi riêng biệt.
Bruce Ediger

@BruceEdiger: Thật là một niềm vui khi nhận được một nhận xét từ BE quý. Cảm ơn! Tôi tin rằng lý do 3 bao gồm nhận xét của bạn, không?
Jonathan Ben-Avraham

1
Tôi đã suy nghĩ nhiều hơn về việc mã nguồn của vỏ sẽ phức tạp đến mức nào nếu nó phải xử lý các đường ống cho các quy trình bên ngoài và đưa đầu ra của một lệnh nội bộ giống như giả thuyết lsvà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.
Bruce Ediger

1
Tôi sợ nhất nếu không phải tất cả 5 điểm của bạn đều là tranh luận. 1: ls là (hy vọng) độc lập với việc thực hiện hệ thống tệp. Điều đó tùy thuộc vào kernel để cung cấp giao diện nhất quán cho thư viện và ứng dụng tiêu chuẩn. 2: ls có khả năng ít phụ thuộc vào HĐH hơn vỏ. 3: đạn pháo chắc chắn cho phép tích hợp trong đường ống. 4: shell chắc chắn cho phép các nội trang được chạy trong nền. 5: đó là khá chủ quan.
jlliagre

1
@ JonathanBen-Avraham @BruceEdiger Không có vỏ đã xử lý trường hợp đường ống cho các phần tử có vỏ con? ví dụ bashđầu ra alias | grep ls. đầu vàocat /etc/passwd | while read a; do echo "$a"; done
Matt

2

lskhô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 PATHcó thể không được thiết lập đúng và tập lệnh đang sử dụng commandnhư 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ợ -vtù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-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à zstatcó thể phục vụ một chức năng tương tự.


2

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 lschương trình GNU trên Linux. So sánh kích thước thực thi của lsđến bashdashvỏ 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 lstính năng đầy đủ như phiên bản GNU trong bashsẽ tăng kích thước thực thi lên 10%. Nó có kích thước gần giống như dashvỏ đầ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 killtí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 ( truefalseđơ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ỏ.


1

cdđược tích hợp vào shell, lslà một chương trình riêng biệt mà bạn sẽ thấy /bin/ls.


0

Đ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
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.