cd
là một vỏ được ủy quyền POSIX :
Nếu một lệnh đơn giản dẫn đến một tên lệnh và một danh sách các đối số tùy chọn, các hành động sau sẽ được thực hiện:
- Nếu tên lệnh không chứa bất kỳ dấu gạch chéo nào, bước thành công đầu tiên trong chuỗi sau sẽ xảy ra:
...
- Nếu tên lệnh khớp với tên của một tiện ích được liệt kê trong bảng sau, tiện ích đó sẽ được gọi.
...
cd
...
- Nếu không, lệnh sẽ được tìm kiếm bằng cách sử dụng ...
Mặc dù điều này không nói rõ ràng rằng nó phải được tích hợp sẵn, nhưng thông số kỹ thuật tiếp tục nói, trong phần mô tả vềcd
:
Vì 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.
Từ bash
hướng dẫn :
Các lệnh dựng sẵn shell sau đây được kế thừa từ Bourne Shell. Các lệnh này được thực hiện theo quy định của tiêu chuẩn POSIX.
...
cd
cd [-L|[-P [-e]]] [directory]
Tôi cho rằng bạn có thể nghĩ về một kiến trúc cd
không cần phải là một kiến trúc . Tuy nhiên, bạn phải xem những gì tích hợp ngụ ý. Nếu bạn viết mã đặc biệt vào trình bao để thực hiện điều gì đó cho một lệnh nào đó, bạn sắp hoàn thành việc dựng sẵn. Bạn càng làm, tốt hơn là chỉ cần có một nội dung.
Ví dụ, bạn có thể có shell có IPC để giao tiếp với các quy trình con và sẽ có một cd
chương trình kiểm tra sự tồn tại của thư mục và liệu bạn có được phép truy cập hay không và sau đó giao tiếp với shell để bảo nó thay đổi danh mục. Tuy nhiên, sau đó bạn sẽ phải kiểm tra xem quy trình giao tiếp với bạn có phải là trẻ em không (hoặc chỉ thực hiện các phương tiện giao tiếp đặc biệt với trẻ em, như mô tả tệp đặc biệt, bộ nhớ dùng chung, v.v.) và nếu thực tế quá trình này chạy cd
chương trình đáng tin cậy hoặc một cái gì đó khác. Đó là cả một con giun.
Hoặc bạn có thể có một cd
chương trình thực hiện chdir
cuộc gọi hệ thống và khởi động một shell mới với tất cả các biến môi trường hiện tại được áp dụng cho shell mới, và sau đó giết shell cha của nó (bằng cách nào đó) khi hoàn thành. 1
Tồi tệ hơn, bạn thậm chí có thể có một hệ thống trong đó một quy trình có thể thay đổi môi trường của các quy trình khác (tôi nghĩ về mặt kỹ thuật bạn có thể làm điều này với trình gỡ lỗi). Tuy nhiên, một hệ thống như vậy sẽ rất, rất dễ bị tổn thương.
Bạn sẽ thấy mình thêm ngày càng nhiều mã để bảo mật các phương thức như vậy và đơn giản hơn đáng kể để đơn giản hóa nó thành một nội dung.
Rằng một cái gì đó là một thực thi không ngăn nó trở thành một nội dung. Trường hợp tại điểm:
echo
và test
echo
và test
là các tiện ích bắt buộc POSIX ( /bin/echo
và /bin/test
). Tuy nhiên, gần như mọi vỏ phổ biến đều có tích hợp echo
và test
. Tương tự, kill
cũng được tích hợp sẵn như một chương trình. Những người khác bao gồm:
sleep
(không phổ biến)
time
false
true
printf
Tuy nhiên, có một số trường hợp lệnh không thể là gì ngoài lệnh dựng sẵn. Một trong số đó là cd
. Thông thường, nếu đường dẫn đầy đủ không được chỉ định và tên lệnh khớp với tên của nội trang, một hàm phù hợp với lệnh đó được gọi. Tùy thuộc vào vỏ, hành vi của các BUILTIN và của thực thi có thể khác nhau (điều này đặc biệt là vấn đề đốiecho
, trong đó có hành vi cực kỳ khác nhau . Nếu bạn muốn chắc chắn về hành vi, nó là thích hợp hơn để gọi thực thi bằng cách sử dụng đường dẫn đầy đủ và đặt các biến như POSIXLY_CORRECT
(ngay cả khi đó không có đảm bảo thực sự).
Về mặt kỹ thuật, không có gì ngăn cản bạn cung cấp HĐH cũng là một hệ vỏ và có mọi lệnh dưới dạng dựng sẵn. Gần cuối cùng là BusyBox nguyên khối . BusyBox là một nhị phân duy nhất, mà (tùy thuộc vào tên mà nó được gọi) có thể hoạt động như bất kỳ trong số hơn 240 chương trình , bao gồm cả Almquist Shell ( ash
). Nếu bạn không đặt PATH
trong khi chạy BusyBox ash
, các chương trình có sẵn trong BusyBox vẫn có thể truy cập được mà bạn không chỉ định a PATH
. Chúng gần giống với các phần tử dựng vỏ, ngoại trừ bản thân phần vỏ đó là một dạng dựng sẵn của BusyBox.
Nếu bạn nhìn vào dash
nguồn, luồng thực thi là như thế này (tất nhiên, với các chức năng bổ sung có liên quan khi đường ống và những thứ khác được sử dụng):
main
→ cmdloop
→ evaltree
→evalcommand
evalcommand
sau đó sử dụng findcommand
để xác định lệnh là gì Nếu nó là một nội trang, thì :
case CMDBUILTIN:
if (spclbltin > 0 || argc == 0) {
poplocalvars(1);
if (execcmd && argc > 1)
listsetvar(varlist.list, VEXPORT);
}
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
if (exception == EXERROR && spclbltin <= 0) {
FORCEINTON;
break;
cmdentry.u.cmd
là một struct
( struct builtincmd
), một trong số các thành viên của nó là một con trỏ hàm, với một chữ ký điển hình là main
: (int, char **)
. Các evalbltin
cuộc gọi chức năng (tùy thuộc vào việc dựng sẵn là eval
lệnh hay không) hoặc là evalcmd
, hoặc con trỏ chức năng này. Các chức năng thực tế được xác định trong các tập tin nguồn khác nhau. echo
, ví dụ, là :
int
echocmd(int argc, char **argv)
{
int nonl;
nonl = *++argv ? equal(*argv, "-n") : 0;
argv += nonl;
do {
int c;
if (likely(*argv))
nonl += print_escape_str("%s", NULL, NULL, *argv++);
if (nonl > 0)
break;
c = *argv ? ' ' : '\n';
out1c(c);
} while (*argv);
return 0;
}
Tất cả các liên kết đến mã nguồn trong phần này là dựa trên số dòng, vì vậy chúng có thể thay đổi mà không cần thông báo trước.
1 hệ thống POSIX có thể cd
thực thi được .
Lưu ý bên:
Có rất nhiều bài viết xuất sắc trên Unix & Linux liên quan đến hành vi shell. Đặc biệt:
Nếu bạn chưa nhận thấy một mô hình trong các câu hỏi được liệt kê cho đến nay, gần như tất cả chúng đều liên quan đến Stéphane Chazelas .
type
lệnh