2016-09-05 15 views
6

Khi tôi làm:hành vi Odd trong bash (và có thể vỏ khác?)

/bin/bash -c 'cat /proc/$$/cmdline' 

Kết quả tôi nhận được là:

cat/proc/25050/cmdline 

Trong khi đầu ra mong đợi của tôi là:

/bin/bash -c 'cat /proc/$$/cmdline' 

Mặt khác, khi tôi làm:

/bin/bash -c 'echo $$; cat /proc/$$/cmdline' 

tôi nhận được đầu ra mong đợi, đó là:

28259 
/bin/bash-cecho $$; cat /proc/$$/cmdline 

Nó có vẻ như là $$ mèo pid hơn pid bash/sh của.
Tại sao điều này?
Vỏ có thực hiện một số loại phân tích và kiểu dáng execve() thay thế không? Nếu vậy, làm thế nào nó biết PID của mèo trước khi nó thay thế?

Trả lời

4

Để hiểu hành vi này, người ta phải tìm ra cách bash thực hiện các lệnh được truyền cho nó trên dòng lệnh. Điểm mấu chốt là nếu lệnh đủ đơn giản, không có fork (hoặc clone hoặc bất kỳ thứ gì tương tự).

$ strace -f -e clone,execve /bin/bash -c 'cat /proc/$$/cmdline' 
execve("/bin/bash", ["/bin/bash", "-c", "cat /proc/$$/cmdline"], [/* 80 vars */]) = 0 
execve("/bin/cat", ["cat", "/proc/2942/cmdline"], [/* 80 vars */]) = 0 
cat/proc/2942/cmdline+++ exited with 0 +++ 
$ 

OTOH nếu lệnh phức tạp hơn, bash dĩa:

$ strace -f -e clone,execve /bin/bash -c 'echo $$; cat /proc/$$/cmdline' 
execve("/bin/bash", ["/bin/bash", "-c", "echo $$; cat /proc/$$/cmdline"], [/* 80 vars */]) = 0 
2933 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ff64e6779d0) = 2934 
Process 2934 attached 
[pid 2934] execve("/bin/cat", ["cat", "/proc/2933/cmdline"], [/* 80 vars */]) = 0 
/bin/bash-cecho $$; cat /proc/$$/cmdline[pid 2934] +++ exited with 0 +++ 
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2934, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- 
+++ exited with 0 +++ 
$ 

Nó có vẻ như là $$ mèo pid hơn pid bash/sh của.

Thực sự là cả hai. bashexecve s cat trực tiếp, do đó, người ta trở thành người khác.

Để hiểu chính xác những gì cần thiết cho hành vi không có ngã ba, chúng ta cần xem mã nguồn. Có nhận xét này:

 /* 
     * IF 
     * we were invoked as `bash -c' (startup_state == 2) AND 
     * parse_and_execute has not been called recursively AND 
     * we're not running a trap AND 
     * we have parsed the full command (string == '\0') AND 
     * we're not going to run the exit trap AND 
     * we have a simple command without redirections AND 
     * the command is not being timed AND 
     * the command's return status is not being inverted 
     * THEN 
     * tell the execution code that we don't need to fork 
     */ 

Source

+0

tôi thấy sản lượng này khi tôi straced nó là tốt. Khi nào nó xác định rằng lệnh không phức tạp và sau khi mã hóa nó xác định rằng nó không cần phải kích hoạt bất kỳ tiến trình con nào (như là kết quả của ';' hoặc '||' hoặc '&&' hoặc '|') thì nó đơn giản là ' execve 's lệnh vượt qua nó. Nếu không thì nó là 'clone' và sau đó là 'execve' trong child/clone. Những gì tôi không nhận được là lý do tại sao. – ffledgling

+0

@ffledgling Có một chú thích trong nguồn 'IF chúng ta được gọi là \' bash -c '(startup_state == 2) VÀ parse_and_execute chưa được gọi đệ quy và chúng ta không chạy một cái bẫy VÀ chúng ta có phân tích cú pháp lệnh đầy đủ (chuỗi == '\ 0') VÀ chúng ta sẽ không chạy bẫy thoát VÀ chúng ta có một lệnh đơn giản mà không cần chuyển hướng VÀ lệnh không được hẹn giờ VÀ trạng thái trả về của lệnh không phải là bị đảo ngược THEN cho biết mã thực thi mà chúng tôi không cần phải ngã ba. –

+0

Bạn có muốn thêm câu trả lời này vào câu trả lời và liên kết với dòng có liên quan trong nguồn chính thức không? – ffledgling

Các vấn đề liên quan