Không có yêu cầu rằng người đầu tiên của các đối số chịu bất kỳ liên quan đến tên của file thực thi:
int main(void)
{
char *args[3] = { "rip van winkle", "30", 0 };
execv("/bin/sleep", args);
return 1;
}
Hãy thử nó - trên máy Mac (sau ba bài kiểm tra):
make x; ./x & sleep 1; ps
Kết quả đầu ra thứ ba là:
MiniMac JL: make x; ./x & sleep 1; ps
make: `x' is up to date.
[3] 5557
PID TTY TIME CMD
5532 ttys000 0:00.04 -bash
5549 ttys000 0:00.00 rip van winkle 30
5553 ttys000 0:00.00 rip van winkle 30
5557 ttys000 0:00.00 rip van winkle 30
MiniMac JL:
comments EBM:
Yeah, và điều này làm cho nó thậm chí còn kỳ lạ hơn. Trong kịch bản bash thử nghiệm của tôi (đích của execve), tôi không thấy giá trị của những gì execve có trong arg [0] bất cứ nơi nào - không phải trong môi trường, và không phải là $ 0.
Sửa đổi thử nghiệm - tập lệnh có tên 'bash'.kịch bản ':
#!/bin/bash
echo "bash script at sleep (0: $0; *: $*)"
sleep 30
Và một chương trình sửa đổi:
int main(void)
{
char *args[3] = { "rip van winkle", "30", 0 };
execv("./bash.script", args);
return 1;
}
Điều này mang lại sản lượng ps:
bash script at sleep (0: ./bash.script; *: 30)
PID TTY TIME CMD
7804 ttys000 0:00.11 -bash
7829 ttys000 0:00.00 /bin/bash ./bash.script 30
7832 ttys000 0:00.00 sleep 30
Có hai khả năng như tôi nhìn thấy nó:
- Các hạt nhân juggles dòng lệnh khi thực hiện kịch bản thông qua dòng shebang ('
#!/bin/bash
'), hoặc
- Bản thân Bash sẽ liên kết với danh sách đối số của nó.
Làm thế nào để thiết lập sự khác biệt? Tôi cho rằng việc sao chép vỏ để một cái tên thay thế, và sau đó sử dụng cái tên thay thế trong công việc sẽ cho chúng ta biết điều gì đó:
$ cp /bin/bash jiminy.cricket
$ sed "s%/bin/bash%$PWD/jiminy.cricket%" bash.script > tmp
$ mv tmp bash.script
$ chmod +w bash.script
$ ./x & sleep 1; ps
[1] 7851
bash script at sleep (0: ./bash.script; *: 30)
PID TTY TIME CMD
7804 ttys000 0:00.12 -bash
7851 ttys000 0:00.01 /Users/jleffler/tmp/soq/jiminy.cricket ./bash.script 30
7854 ttys000 0:00.00 sleep 30
$
này, tôi nghĩ rằng, chỉ ra rằng hạt nhân ghi đè argv[0]
khi cơ chế công việc được sử dụng.
Phát biểu bình luận bằng nategoose: '#!/Path/to/chương trình'
MiniMac JL: pwd
/Users/jleffler/tmp/soq
MiniMac JL: cat al.c
#include <stdio.h>
int main(int argc, char **argv)
{
while (*argv)
puts(*argv++);
return 0;
}
MiniMac JL: make al.c
cc al.c -o al
MiniMac JL: ./al a b 'c d' e
./al
a
b
c d
e
MiniMac JL: cat bash.script
#!/Users/jleffler/tmp/soq/al
echo "bash script at sleep (0: $0; *: $*)"
sleep 30
MiniMac JL: ./x
/Users/jleffler/tmp/soq/al
./bash.script
30
MiniMac JL:
Điều đó cho thấy rằng đó là công việc cơ chế, chứ không phải bất kỳ chương trình như Bash, mà điều chỉnh giá trị của argv[0]
. Vì vậy, khi một nhị phân được thực thi, giá trị của argv[0]
không được điều chỉnh; khi một kịch bản được thực hiện thông qua shebang, danh sách đối số được điều chỉnh bởi hạt nhân; argv[0]
là nhị phân được liệt kê trên shebang; nếu có một đối số sau shebang, nó sẽ trở thành argv[1]
; đối số tiếp theo là tên của tệp tập lệnh, theo sau là bất kỳ đối số nào còn lại từ cuộc gọi execv()
hoặc tương đương.
MiniMac JL: cat bash.script
#!/Users/jleffler/tmp/soq/al -arg0
#!/bin/bash
#!/Users/jleffler/tmp/soq/jiminy.cricket
echo "bash script at sleep (0: $0; *: $*)"
sleep 30
MiniMac JL: ./x
/Users/jleffler/tmp/soq/al
-arg0
./bash.script
30
MiniMac JL:
Bạn cần dấu ngoặc kép; và có lẽ một null char * để chấm dứt danh sách các đối số, giả sử bạn đang sử dụng execl(). –
Tôi sẽ dùng từ ngữ của bạn, nhưng thật thú vị, tôi đã tạo một bài kiểm tra thực thi một tập lệnh bash đơn giản phát ra $ 0, và ngay cả khi tôi sử dụng tên chương trình "được làm sạch", $ 0 vẫn sẽ là đường dẫn đầy đủ (được xây dựng từ execve() của đối số đầu tiên, sau đó, tôi giả định). – EBM
@Johnathan: Đổ lỗi cho Python. –