다음 줄은 생성되지만 file_c-6.txt
출력됩니다 5
.
$ i=5; ls file_a-${i}.txt file_b-${i}.txt > file_c-$(( ++i )).txt; echo $i
5
$ cat file_c-6.txt
file_a-5.txt
file_b-5.txt
제거되면 >
다음이 나열 file_c-6.txt
되고 출력됩니다 5
.
i
첫 번째 예의 값을 유지하지 않는 이유를 이해할 수 없습니다.
$ i=5; ls file_a-${i}.txt file_b-${i}.txt file_c-$(( ++i )).txt; echo $i
file_a-5.txt file_b-5.txt file_c-6.txt
6
답변1
ls
이 명령을 strace에서 실행해 보면, 사용된 버전은 서브쉘에서 명령을 시작하는 반면, echo를 사용한 버전은 기존 쉘에서 모든 명령을 실행하는 것을 볼 수 있습니다 .
출력 비교
$ strace -f /bin/bash -o trace.txt -c 'i=5; echo $i; echo file_c-$((++i)).txt; echo $i'
5
6
6
반대하다
strace -f /bin/bash -o trace.txt -c 'i=5; echo $i; ls > file_c-$((++i)).txt; echo $i'
5
5
첫 번째 항목에서 다음을 볼 수 있습니다.
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
두 번째에서는:
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
마지막 예에서는 clone
새 프로세스가 입력되었으므로(1258 -> 1259) 이제 하위 프로세스에 있습니다. file_c-6.txt를 여는 것은 $((++i))
서브셸에서 이를 평가 했으며 ls
실행 시 stdout이 해당 파일로 설정되었음을 의미합니다.
마지막으로 하위 프로세스가 종료되는 것을 확인하고 하위 프로세스를 다시 가져와 중단한 부분부터 계속합니다. $i
5로 설정하면 이것이 다시 에코됩니다.
(자식 프로세스의 변경 사항을 가져오기 위해 상위 프로세스에서 명시적으로 작업을 수행하지 않는 한 하위 프로세스의 변수 변경 사항은 상위 프로세스로 흘러가지 않는다는 점을 기억하세요.)