Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Bash & the POSIX Shell Module 6

Redirection, pipes and substitution interview questions

Interview questions on redirection, pipes and substitution: warm-ups, then what each harder question tests and how a good answer starts.

15 questions: 5 warm-ups and 10 with model answers · Levels: Fresher to senior

Warm-up questions

Short questions with short answers, each answered in full.

  1. Fresher to mid

    Name the three standard streams with their numbers, and say what 2>&1 does.

    Standard input is descriptor 0, where a command reads, by default from the keyboard. Standard output is descriptor 1, for results, and standard error is descriptor 2, for warnings and errors; in a terminal both go to the screen. 2>&1 makes descriptor 2 a copy of descriptor 1 as it points at that moment, so errors go wherever results are going. Because redirections run from left to right, cmd > out.txt 2>&1 puts both streams in out.txt, while cmd 2>&1 > out.txt sends errors to the old standard output, the terminal or a pipe, and only the results to the file. Piped into sed, the second form let the warning alone through the pipe.

    From the lesson Redirection: stdin, stdout, stderr, /dev/null

  2. Fresher to mid

    What status does a pipeline return, how do you see every stage's status, and what does pipefail change?

    A pipeline's status is its last command's: false | true returns 0 because true came last. PIPESTATUS holds every stage's status as an array, ${PIPESTATUS[0]} for the first stage; copy it on the same line, because the next command replaces it. With set -o pipefail, the pipeline returns the status of the rightmost command that failed, or 0 when all of them succeeded, so false | true returns 1. pipefail has been in Bash since 3.0 and is part of POSIX.1-2024.

    From the lesson Pipelines, PIPESTATUS and pipefail

  3. Fresher to mid

    How do <<EOF, <<'EOF' and <<-EOF differ?

    Answered in the lesson Here-documents and here-strings

  4. Fresher to mid

    What does exec do when it is given redirections and no command, and how do exec 3>&1 and exec 3> trace.log differ?

    Without a command, exec runs no program: it applies its redirections to the shell that runs it, and they stay in force for every later command of the script until another exec changes them. exec 3> trace.log opens descriptor 3 on trace.log, emptied first, so echo text >&3 writes into the file. exec 3>&1 opens no file: it makes 3 a copy of descriptor 1 as it points at that moment, usually to save standard output before moving it, so that exec 1>&3 3>&- can restore it later. Every program the script starts inherits both kinds, so close a descriptor with exec 3>&- once it is no longer needed; a write after the close fails with "Bad file descriptor".

    From the lesson File descriptors and exec redirections

  5. Fresher to mid

    What happens to trailing newlines in command substitution, and how would you keep them?

    Bash deletes every newline at the end of the captured output, however many there are; newlines inside the output stay. A file holding alpha and beta followed by two blank lines, 13 bytes, is captured by out=$(cat lines.txt) as 10 bytes. To keep them, print a sentinel character after the command inside the same substitution and remove it afterwards: out=$(cat lines.txt; echo .), then out=${out%.}. Bash now deletes only the newline after the dot, the file's own newlines are no longer at the end, and removing the dot leaves all 13 bytes. Quote the variable when you use it, as "$out", or word splitting drops the newlines again.

    From the lesson Command and process substitution

Questions with model answers

What each question tests, the first step of a good answer and the follow-ups to expect.

  1. Fresher to mid

    A nightly cron entry runs /opt/jobs/sync.sh 2>&1 >> /var/log/sync.log. The log fills with progress lines, but on the night the remote host was down it holds no error at all, and the error text arrived in the job's cron mail instead. Explain where each stream went, and fix the line.

    What it tests
    Applying the left-to-right order of redirections to a scheduled job, knowing what cron does with output that is not redirected, and choosing >> file 2>&1.
    First step
    Follow the two descriptors. Under cron both start at the output cron collects and mails. 2>&1 copies that, so the errors keep going to the mail, and >> /var/log/sync.log then moves only descriptor 1 to the log. Swap the order: /opt/jobs/sync.sh >> /var/log/sync.log 2>&1.
    Follow-ups

    From the lesson Redirection: stdin, stdout, stderr, /dev/null

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.

    Opening the model answers with your pass…

    Model answers open with any MySmartCoPilot pass.

    • Pro pass · 1 week₹79$2.99
    • 30 days₹179$5.99
    • 1 year₹1,699$45

    One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

    It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 4 minutes
  2. Mid to senior

    setup.sh begins with #!/bin/sh and set -e, then runs ./migrate.sh &> migrate.log and ./seed.sh. Run with bash on a laptop, migrate.log fills. The build server runs ./setup.sh, and its sh is dash: migrate.log stays empty, the migration's output lands in the job console, and seed.sh sometimes fails on missing tables. Explain all three, and fix it.

    What it tests
    Knowing that &> is Bash syntax, how dash splits it into & and a bare redirection, what that does to the order of the steps and to set -e, and how to catch it before it runs.
    First step
    Read the line as dash does: ./migrate.sh & starts the migration in the background, and > migrate.log is a command of its own that only empties the file. The output still goes to the console, and seed.sh starts at once, while the migration is still running. Write ./migrate.sh > migrate.log 2>&1.
    Follow-ups

    From the lesson Redirection: stdin, stdout, stderr, /dev/null

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  3. Mid to senior

    A monitor runs under set -o pipefail and pages when if dump_journal | grep -q 'disk full' succeeds. On quiet days it pages as it should. On a busy day the dump was 100,000 lines long with 'disk full' near the top, and no page fired. Why, and how would you fix the check?

    What it tests
    Seeing that grep -q stops reading at the first match, that the writer then dies of SIGPIPE, that pipefail turns its 141 into a failed if, and fixing it without hiding a real failure of the dump.
    First step
    grep -q exits as soon as it finds the line. dump_journal, still writing, gets SIGPIPE and exits 141, and under pipefail that is the pipeline's status, so the if takes the else branch although the line was found. A small dump fits into the pipe before grep exits, which is why quiet days worked.
    Follow-ups

    From the lesson Pipelines, PIPESTATUS and pipefail

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  4. Fresher to mid

    A clean-up step runs sort users.txt | uniq > users.txt to remove duplicate lines. Afterwards users.txt is empty, every time, although sort and uniq both exit 0. What happened, and how would you remove the duplicates in place safely?

    What it tests
    Knowing that the stages of a pipeline start together, that > empties its file when the shell sets up the last stage, and replacing the file only after the whole pipeline has succeeded.
    First step
    The shell starts both stages at once and opens users.txt for uniq's > as it starts the last stage; > empties the file, so sort reads 0 bytes and uniq writes nothing. Write to a new file and rename it over users.txt only when the pipeline succeeded, or let sort write the file itself with sort -u -o users.txt users.txt.
    Follow-ups

    From the lesson Pipelines, PIPESTATUS and pipefail

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  5. Fresher to mid

    deploy.sh writes app.conf with cat > app.conf <<EOF, and someone typed the database password into the body by hand: db_password=Tr0ub4$$dor. After the deploy the database rejects the password, and app.conf shows Tr0ub4, then a five-digit number, then dor. Explain what Bash did, and fix the script.

    What it tests
    Knowing that an unquoted here-document expands the dollar signs of its own text, that $$ is the process ID of the shell, choosing <<'EOF' or \$ escapes, and moving the secret out of the script.
    First step
    The body of <<EOF is expanded like a double-quoted string, so $$ in the typed password became the process ID of the shell running deploy.sh, a different number on every run. Quote the delimiter, <<'EOF', so the body is written as typed; when other lines must still expand, write each literal dollar sign as \$.
    Follow-ups

    From the lesson Here-documents and here-strings

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  6. Fresher to mid

    deploy.sh writes nginx.conf with cat > nginx.conf <<-EOF, its body and closing EOF indented with tabs. An editor then replaced every tab with four spaces. The next deploy printed a warning that a here-document was delimited by end-of-file, nginx.conf gained four spaces on every line, and the script's last lines never ran. Explain each symptom, and prevent a repeat.

    What it tests
    Knowing that <<- strips tabs only, so the closing line no longer matches, that Bash then takes the rest of the file as the body, and that ShellCheck's SC1040 catches the mistake where bash -n does not.
    First step
    <<- strips leading tabs, never spaces. The body lines keep their four spaces, and the closing line now reads four spaces and EOF, which is not the delimiter, so Bash reads to the end of the file looking for it: the script's remaining lines become part of nginx.conf instead of running, and Bash warns about the missing delimiter.
    Follow-ups

    From the lesson Here-documents and here-strings

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  7. Mid to senior

    Cron runs maint.sh >> maint.log 2>&1 every night. Its prune function starts with exec 4>&1 > /dev/null to hide rm's chatter and ends with exec 1>&4 4>&-. On nights with nothing to prune, maint.log keeps the error lines but loses every normal line after prune. Explain why, and fix it.

    What it tests
    Knowing that an exec redirection changes the whole shell until changed again, finding the path that skips the restore, and moving the redirection onto the call, where Bash undoes it by itself.
    First step
    exec 4>&1 > /dev/null changes the descriptors of the script's shell, not of the function. On a quiet night prune returns early, before exec 1>&4 4>&-, so descriptor 1 stays on /dev/null for the rest of the run, while descriptor 2 still points at the log, which is why the errors survive.
    Follow-ups

    From the lesson File descriptors and exec redirections

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 4 minutes
  8. Mid to senior

    export.sh prints 3,000 CSV rows on standard output and runs as ./export.sh | gzip > rows.csv.gz. Someone added echo "exported $n rows" every 1,000 rows, and the decompressed file now has 3,003 lines. Where should the progress go so that the data stays clean, and how does the person running the export still see it?

    What it tests
    Keeping data on standard output and messages on standard error, knowing that a pipe carries descriptor 1 only, and checking the fix by counting the rows that reach the file.
    First step
    The pipe to gzip carries descriptor 1 only, so whatever is echoed there becomes data. Send the progress to standard error with >&2, or to descriptor 3 opened as a copy of it with exec 3>&2; the screen still shows it, because only descriptor 1 goes into the pipe. Then check: gzip -dc rows.csv.gz | wc -l must say 3,000.
    Follow-ups

    From the lesson File descriptors and exec redirections

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  9. Mid to senior

    release.sh starts with set -e, runs echo "tagging release-$(cat VERSION)" and then writes release-$(cat VERSION) to tag.txt. One night VERSION was missing: cat printed an error, yet the script ended with status 0 and tagged the build release-. Why did set -e not stop it, and how would you fix the script?

    What it tests
    Knowing that set -e reacts to the status of a command, not of a substitution inside its arguments, that only an assignment passes a substitution's status on, and moving the capture onto its own checked line.
    First step
    set -e looks at the status of each command. The substitution is part of echo's argument: cat fails inside it, but the line's status is echo's 0, so the script goes on with an empty version. Capture first, with version=$(cat VERSION) on its own line: that assignment takes cat's status, and set -e stops the script there.
    Follow-ups

    From the lesson Command and process substitution

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  10. Mid to senior

    added.sh runs under set -euo pipefail and reports new accounts with comm -13 <(sort old-users.txt) <(sort "$today") > added.txt. The morning today's export was missing, sort printed an error, yet the script said "added: 0 accounts" and exited 0. Why did none of the three options stop it, and how would you make it fail?

    What it tests
    Knowing that the shell checks comm's status and never a process substitution's, that pipefail covers pipelines only, and making the script check its inputs or wait for each substitution.
    First step
    The failure happened inside <( ), and Bash does not fold a process substitution's status into the command that reads it. comm compared the old list against an empty input, found no new line and exited 0, so set -e and pipefail saw success. Check both inputs before the comparison, or wait for the substitution: wait $! returned sort's failure here.
    Follow-ups

    From the lesson Command and process substitution

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes

All Bash & the POSIX Shell interview questions · The Bash & the POSIX Shell track

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.