tee: Usage, Options & Common CI Errors
tee splits a stream: it passes data through while also saving a copy to a file.
tee lets you log output and keep it flowing down the pipe. In CI it is the trick for writing root-owned files (sudo tee) and the reason a pipeline can hide a failing command exit code.
What it does
tee reads stdin and writes it to both stdout and one or more files. It is used to capture build logs while still displaying them, and to write files that need elevated permissions.
Common usage
make build 2>&1 | tee build.log
echo "deb ..." | sudo tee /etc/apt/sources.list.d/x.list
some_cmd | tee -a run.log # append
echo "127.0.0.1 host" | sudo tee -a /etc/hosts
cmd | tee out.txt | grep ERROROptions
| Flag | What it does |
|---|---|
| -a / --append | Append to files instead of overwriting |
| -i / --ignore-interrupts | Ignore SIGINT |
| (sudo) tee | Write a file as root from a non-root pipe |
Common errors in CI
The big gotcha: cmd | tee log.txt exits with tee's status, not cmd's - a failing build can look green because tee succeeded. Use set -o pipefail so the pipeline reflects cmd's failure (or check ${PIPESTATUS[0]} in bash). "tee: /etc/...: Permission denied" means you piped into a privileged path without sudo tee. Appending without -a truncates the file each run.