Hiểu các lệnh dựng sẵn shell


12

Trong hướng dẫn bash , nó được viết rằng

Builtin commands are contained >>> within <<< the shell itself

Ngoài ra, câu trả lời này nói rằng

A built-in command is simply a command that the shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

Khi tôi chạy compgen -bvề bash 4.4, tôi nhận được một danh sách tất cả vỏ được xây dựng trong các lệnh. Tôi thấy ví dụ đó [killđược liệt kê là shell dựng. Nhưng địa điểm thực tế của họ là:

/usr/bin/[
/bin/kill

Tôi nghĩ rằng đó là một builtinphương tiện mà lệnh được biên dịch thành /bin/bashtệp thực thi. Vì vậy, điều thực sự làm tôi bối rối: Xin hãy sửa lỗi cho tôi, nhưng làm thế nào một lệnh riêng biệt có thể là một builtin, khi nó thực sự không phải là một phần của vỏ?


1
Một số lệnh ban đầu tồn tại như các tiện ích riêng biệt. Sự hiện diện của họ bây giờ là để tuân thủ tiêu chuẩn POSIX, tính di động, cũng như khả năng tương thích ngược. Shell thực hiện một số như được xây dựng cho hiệu suất. Có thể có lý do khác, nhưng đó là về nó mà không có quá nhiều chi tiết.
Sergiy Kolodyazhnyy

1
Một lý do khác mà tôi có thể nghĩ đến là bởi vì một số lệnh tích hợp là cần thiết cho shell, đặc biệt là execđể thao tác mô tả tệp và eval để đánh giá các lệnh. Chúng không cần thiết như các lệnh độc lập
Sergiy Kolodyazhnyy

Câu trả lời:


16

Các lệnh được tích hợp vào shell thường được tích hợp do tăng hiệu năng mà điều này mang lại. Gọi bên ngoài printf , ví dụ, chậm hơn so với sử dụng tích hợp printf.

Vì một số tiện ích không cần phải được xây dựng, trừ khi chúng đặc biệt, như thế cd, chúng cũng được cung cấp dưới dạng tiện ích bên ngoài . Điều này là để các tập lệnh sẽ không bị hỏng nếu chúng được giải thích bởi một trình bao không cung cấp tương đương.

Một số phần mềm tích hợp của shell cũng cung cấp các phần mở rộng cho lệnh tương đương bên ngoài. Bash printf, ví dụ là có thể làm

$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world

(in ra một biến) mà bên ngoài /usr/bin/printfđơn giản là không thể thực hiện được vì nó không có quyền truy cập vào các biến shell trong phiên shell hiện tại (và không thể thay đổi chúng).

Các tiện ích được tích hợp cũng không có hạn chế là dòng lệnh mở rộng của chúng phải ngắn hơn một độ dài nhất định. Đang làm

printf '%s\n' *

do đó là an toàn nếu printflà một lệnh tích hợp shell. Hạn chế về độ dài của dòng lệnh xuất phát từ execve()chức năng thư viện C được sử dụng để thực thi lệnh bên ngoài. Nếu dòng lệnh và môi trường hiện tại lớn hơn ARG_MAXbyte (xem getconf ARG_MAXtrong shell), lệnh gọi execve()sẽ thất bại. Nếu tiện ích được tích hợp vào shell, execve()thì không cần phải gọi.

Được xây dựng trong các tiện ích được ưu tiên hơn các tiện ích được tìm thấy trong $PATH. Để tắt lệnh tích hợp sẵn bash, hãy sử dụng, vd

enable -n printf

Có một danh sách ngắn các tiện ích cần được tích hợp vào vỏ (lấy từ danh sách tích hợp đặc biệt của tiêu chuẩn POSIX )

break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset

Chúng cần được xây dựng vì chúng trực tiếp thao tác với môi trường và luồng chương trình của phiên shell hiện tại. Một tiện ích bên ngoài sẽ không thể làm điều đó.

Thật thú vị, cdkhông phải là một phần của danh sách này, nhưng POSIX nói như sau về điều đó:

cdảnh hưởng đến môi trường thực thi shell hiện tại, nó luôn được cung cấp dưới dạng shell được tích hợp thường xuyên. Nếu nó được gọi trong một môi trường con hoặc môi trường thực thi tiện ích riêng biệt, chẳng hạn như một trong những điều sau đây:

(cd /tmp)
nohup cd
find . -exec cd {} \;

nó không ảnh hưởng đến thư mục làm việc của môi trường người gọi.

Do đó, tôi cho rằng các tích hợp "đặc biệt" không thể có các đối tác bên ngoài, trong khi cdvề lý thuyết có thể có (nhưng nó sẽ không làm được gì nhiều).


IIRC, chdir/ cdlà các nhị phân bên ngoài trong Unices / pre-Unix rất sớm trước khi forkđược giới thiệu.
Xophmeister

@Xophmeister Solaris 11.4 (beta) vẫn có /usr/bin/cd, nhưng nó sẽ không thực sự thay đổi thư mục làm việc hiện tại. Hướng dẫn của nó nói: /usr/bin/cdkhông có tác dụng đối với quá trình gọi nhưng có thể được sử dụng để xác định xem một thư mục đã cho có thể được đặt làm thư mục hiện tại hay không.
Kusalananda

2
Một lý do khác, khá cụ thể đối với nội dung: nội dung killcũng tốt vì không cần rẽ nhánh một quy trình khác, tốt nếu bạn đạt giới hạn số lượng quy trình.
derobert

7

Bạn (rất dễ hiểu) bối rối bởi thực tế là một số nội dung tồn tại cả dưới dạng nội dung dưới dạng các lệnh bên ngoài. Vì vậy, trong khi bạn nói đúng, chẳng hạn, có một /bin/[lệnh, điều đó không có nghĩa là "vị trí thực tế" của nó nằm trong đó /bin.

Bất kỳ cách dễ dàng nào để kiểm tra điều này là chạy typevới công -atắc sẽ hiển thị tất cả các phiên bản có sẵn của lệnh. Trên hệ thống Arch của tôi, điều đó cho thấy:

$ type -a [
[ is a shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

Lưu ý rằng /sbin, /usr/sbin/bintất cả các liên kết tượng trưng chỉ đến /usr/bin, vì vậy chỉ có một bên ngoài [:

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

Như bạn có thể thấy, [cả hai lệnh dựng sẵn và lệnh bên ngoài, và điều tương tự cũng đúng với nhiều hàm dựng khác. Tuy nhiên, điều đó không làm thay đổi thực tế rằng chúng cũng là các phần tử dựng sẵn, được biên dịch vào chính phần vỏ.


Tại sao lại xa. cung cấp lệnh bên ngoài riêng biệt cho một lệnh nội bộ đã tồn tại? Tại sao chúng trùng lặp?
LoveWithMaths

1
@linuxuser một số tiện ích này được POSIX yêu cầu và bạn không thể biết liệu vỏ mà người dùng tình cờ đang sử dụng cũng sẽ cung cấp nội dung. Đừng nghĩ chúng là lệnh nội bộ của HĐH, chúng chỉ là các lệnh nội bộ của shell và shell có thể thay đổi.
terdon

Bây giờ tôi có 1 nghi ngờ, nếu các lệnh nội bộ được cung cấp bởi shell; Sau đó, ai cung cấp các lệnh bên ngoài? Giống như tôi đã quan sát nhiều lệnh có sẵn như lệnh bên trong cũng như bên ngoài, nhưng tôi không cài đặt chúng một cách rõ ràng; Vậy ai cung cấp lệnh bên ngoài? Distro cung cấp cho họ chính xác?
LoveWithMaths

@linuxuser phụ thuộc vào lệnh và hệ điều hành. Ví dụ, trên Arch Linux của tôi, /bin/printfđược cài đặt bởi coreutilsgói và /bin/killbởi util-linux.
terdon

Tôi xin lỗi nhưng tôi vẫn chưa rõ, những gì ở trên được cung cấp bởi distro? và những gì khác không được cung cấp bởi distro thì ai cung cấp nó.
LoveWithMaths
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.