Nếu bạn chạy nó dưới strace, bạn có thể thấy rằng phiên bản sử dụng ls
khởi động lệnh trong một lớp con, trong đó phiên bản sử dụng echo thực thi tất cả trong shell hiện có.
So sánh đầu ra của
$ strace -f /bin/bash -o trace.txt -c 'i=5; echo $i; echo file_c-$((++i)).txt; echo $i'
5
6
6
chống lại
strace -f /bin/bash -o trace.txt -c 'i=5; echo $i; ls > file_c-$((++i)).txt; echo $i'
5
5
Bạn sẽ thấy trong phần đầu tiên:
1251 execve("/bin/bash", ["/bin/bash", "-c", "i=5; echo $i; echo file_c-$(( ++"...], [/* 19 vars */]) = 0
...
1251 write(1, "5\n", 2) = 2
1251 write(1, "file_c-6.txt\n", 13) = 13
1251 write(1, "6\n", 2) = 2
Và trong lần thứ hai:
1258 execve("/bin/bash", ["/bin/bash", "-c", "i=5; echo $i; ls > file_c-$(( ++"...], [/* 19 vars */]) = 0
...
1258 write(1, "5\n", 2) = 2
...
1258 stat("/bin/ls", {st_mode=S_IFREG|0755, st_size=110080, ...}) = 0
1258 access("/bin/ls", R_OK) = 0
1258 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7301f40a10) = 1259
1259 open("file_c-6.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
1259 dup2(3, 1) = 1
1259 close(3) = 0
1259 execve("/bin/ls", ["ls"], [/* 19 vars */]) = 0
1259 write(1, "71\nbin\nfile_a-5.txt\nfile_b-5.txt"..., 110) = 110
1259 close(1) = 0
1259 munmap(0x7f0e81c56000, 4096) = 0
1259 close(2) = 0
1259 exit_group(0) = ?
1259 +++ exited with 0 +++
1258 <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 1259
1258 rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f7301570d40}, {0x4438a0, [], SA_RESTORER, 0x7f7301570d40}, 8) = 0
1258 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
1258 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1259, si_status=0, si_utime=0, si_stime=0} ---
1258 wait4(-1, 0x7ffd23d86e98, WNOHANG, NULL) = -1 ECHILD (No child processes)
1258 rt_sigreturn() = 0
1258 write(1, "5\n", 2) = 2
Trong ví dụ cuối cùng này, bạn thấy clone
một quy trình mới (từ 1258 -> 1259), vì vậy bây giờ chúng tôi đang ở trong một quy trình con. Việc mở file_c-6.txt có nghĩa là chúng tôi đã đánh giá $((++i))
trong lớp con và việc thực hiện ls
với thiết bị xuất chuẩn của nó được đặt thành tệp đó.
Cuối cùng, chúng ta thấy rằng quy trình con thoát ra, chúng ta gặt đứa trẻ, sau đó chúng ta tiếp tục với nơi chúng ta rời đi ... với $i
thiết lập là 5, và đó là những gì chúng ta lặp lại.
(Hãy nhớ các thay đổi biến trong quy trình con không phù hợp với quy trình cha, trừ khi bạn làm điều gì đó rõ ràng ở cha mẹ để lấy các thay đổi của con)