In Jenkins, you can use the sh
step to run Unix shell scripts.
I was experimenting, and I found that the stdout is not a tty, at least on a Docker image.
What does Jenkins use for capturing stdout and stderr of programs running via the sh
step? Is the same thing used for running the sh
step on a Jenkins node versus on a Docker container?
I ask for my own edification and for some possible practical applications of this knowledge.
To reproduce my experimentation
If you already know an answer, you don’t need to read these details for reproducing. I am just adding this here for reproducibility.
I have the following Jenkins/Groovy code:
docker.image('gcc').inside {
sh '''
gcc -O2 -Wall -Wextra -Wunused -Wpedantic
-Werror write_to_tty.c -o write_to_tty
./write_to_tty
'''
}
The Jenkins log snippet for the sh
step code above is
+ gcc -O2 -Wall -Wextra -Wunused -Wpedantic -Werror write_to_tty.c -o write_to_tty
+ ./write_to_tty
stdout is not a tty.
This compiles and runs the following C code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int stdout_fd = fileno(stdout);
if (!isatty(stdout_fd)) {
fprintf(stderr, "stdout is not a tty.n");
exit(1);
}
char* stdout_tty_name = ttyname(stdout_fd);
if (stdout_tty_name == NULL) {
fprintf(stderr, "Failed to get tty name of stdout.n");
exit(1);
}
FILE* tty = fopen(stdout_tty_name, "w");
if (tty == NULL) {
fprintf(stderr, "Failed to open tty %s.n", stdout_tty_name);
exit(1);
}
fprintf(tty, "Written directly to tty.n");
fclose(tty);
printf("Written to stdout.n");
fprintf(stderr, "Written to stderr.n");
exit(0);
}
2
Answers
I found the source for the
sh
step, which appears to be implemented using theBourneShellScript
class.When not capturing stdout, the command is generated like this:
If I correctly matched the format specifiers to the variables, then the
%s '%s' > '%s' 2>&1
part roughly corresponds toSo it seems that the stdout and stderr of the script is written to a file.
When capturing output, it is slightly different, and is instead
In this case, stdout and stderr are still written to files, just not to the same file.
Aside
For anyone interested in how I found the source code:
sh
step docs, which can be found with a search engineShellStep.java
by drilling down from thesrc
directoryBourneShellScript
class, and based on the import for this class, I knew it was part of the durable task plugin.java
fileI briefly looked at the source here and it seems
stdout
is written to a file and then read from that, Hence it’s not a tty. Also,stderror
, if any, will be written to the log.Here is the Javadoc.