- You're performing the redirection on the
stracecommand, so the redirection will be performed by your interactive shell, andstracewill not be able to see relevant system calls. - The
dup2system call is performed inside of the child before the command execution. By default,stracewill not follow children of your commands, so you won't be able to see the trace of the child itself. You will need to add the-fflag to yourstraceto make sure it also follows the children.
Notice the open and dup2 system calls are performed inside pid 31770, the child of the sh -c... command, before actually executing test.sh.
Duplicating the file descriptors in the parent instead of the child
It is possible (depending on the implementation of your shell) that the duplication will be performed on the parent level before performing the clone. In that case, the parent will need to save the original STDOUT and STDERR file descriptors, and restore them after the child terminates.
$ grep -E 'dup2\(|clone\(|execve\(|(open|write|close|openat)\(.*tmp.txt|F_DUPFD|exit_group' trace.log
1094 execve("/usr/bin/sh", ["sh", "-c", "./test.sh > tmp.txt 2>&1"], 0x7fffd0324118 /* 20 vars */) = 0
1094 openat(AT_FDCWD, "tmp.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3</tmp/tmp.txt>
1094 fcntl(1</dev/pts/0>, F_DUPFD, 10) = 10</dev/pts/0>
1094 dup2(3</tmp/tmp.txt>, 1) = 1</tmp/tmp.txt>
1094 close(3</tmp/tmp.txt>) = 0
1094 fcntl(2</dev/pts/0>, F_DUPFD, 10) = 11</dev/pts/0>
1094 dup2(1</tmp/tmp.txt>, 2) = 2</tmp/tmp.txt>
1094 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f844aa71690) = 1095
1095 execve("./test.sh", ["./test.sh"], 0x7f844aa9dc08 /* 20 vars */) = 0
1095 fcntl(3</tmp/test.sh>, F_DUPFD, 10) = 10</tmp/test.sh>
1095 write(1</tmp/tmp.txt>, "hello\n", 6) = 6
1095 write(2</tmp/tmp.txt>, "./test.sh: 3: ", 14) = 14
1095 write(2</tmp/tmp.txt>, "whatfuckis: not found", 21) = 21
1095 write(2</tmp/tmp.txt>, "\n", 1) = 1
1095 exit_group(127) = ?
1094 dup2(10</dev/pts/0>, 1</tmp/tmp.txt>) = 1</dev/pts/0>
1094 dup2(11</dev/pts/0>, 2</tmp/tmp.txt>) = 2</dev/pts/0>
1094 exit_group(127)
See how before running each dup2 at the beginning, the parent (pid 1094) duplicates file descriptors 1 and 2 into file descriptors 10 and 11 respectively (using the fcntl system call and the F_DUPFD command) .
Then after the child (pid 1095) completes, the parent restores file descriptors 10 and 11 (the original STDOUT and STDERR) back to file descriptors 1 and 2.