ЁЯПл The SchoolтА║ЁЯз╣ Shell scriptingтА║ЁЯФА рдзрдбрд╛ 03 тАФ Pipes рдЖрдгрд┐ redirection: рдХреЙрд░рд┐рдбреЙрд░
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯФА рдзрдбрд╛ 03 тАФ Pipes рдЖрдгрд┐ redirection: рдХреЙрд░рд┐рдбреЙрд░

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 03 ┬╖ рдкреБрдвреЗ: lesson-04-text-tools


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ03. рдкреНрд░рддреНрдпреЗрдХ command рдХрдбреЗ рдЕрд╕рдгрд╛рд░реЗ рддреАрди streams, рдЖрдгрд┐ commands рдирд╛ рдПрдХрдореЗрдХрд╛рдВрд╢реА рд╡ files рд╢реА рдЬреЛрдбрдгрд╛рд░реА plumbing.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдкреНрд░рддреНрдпреЗрдХ command рд▓рд╛ рддреАрди рдХреЙрд░рд┐рдбреЙрд░ рдЕрд╕рддрд╛рдд: рдПрдХ рдЖрдд рдпреЗрдгрд╛рд░рд╛ (stdin, 0), рдПрдХ report рд╕рд╛рдареА рдмрд╛рд╣реЗрд░ рдЬрд╛рдгрд╛рд░рд╛ (stdout, 1), рдЖрдгрд┐ рдПрдХ рддрдХреНрд░рд╛рд░реАрдВрд╕рд╛рдареА (stderr, 2). pipe | рдПрдХрд╛ command рдЪрд╛ рдмрд╛рд╣реЗрд░рдЪрд╛ рдХреЙрд░рд┐рдбреЙрд░ рдкреБрдврдЪреНрдпрд╛ command рдЪреНрдпрд╛ рдЖрддрд▓реНрдпрд╛ рдХреЙрд░рд┐рдбреЙрд░рд▓рд╛ рдЬреЛрдбрддреЛ, рдореНрд╣рдгреВрди рдЪрд╛рд░ рдЫреЛрдЯреЗ tools рдорд┐рд│реВрди рдПрдХрд╛ рдкреНрд░рд╢реНрдирд╛рдЪреЗ рдЙрддреНрддрд░ рджреЗрдК рд╢рдХрддрд╛рдд. > report file рдордзреНрдпреЗ рдкрд╛рдард╡рддреЛ, >> рд╢реЗрд╡рдЯреА рдЬреЛрдбрддреЛ, 2> рддрдХреНрд░рд╛рд░реА рджреБрд╕рд░реАрдХрдбреЗ рдкрд╛рдард╡рддреЛ. рд╕рдЧрд│реЗ рдЪрд╛рд▓рд╡рдгрд╛рд░рд╛ рдирд┐рдпрдо: report рдЖрдгрд┐ log рдХрдзреАрдЪ рдПрдХ рдХреЙрд░рд┐рдбреЙрд░ рд╡рд╛рдЯреВрди рдШреЗрдд рдирд╛рд╣реАрдд.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
  K["тМия╕П stdin 0"] --> C["тЪЩя╕П command"]
  C -->|"1 stdout"| O["ЁЯУД report тЖТ | next ┬╖ > file ┬╖ >> file"]
  C -->|"2 stderr"| E["ЁЯУг log тЖТ 2> file ┬╖ 2>&1 ┬╖ 2>/dev/null"]

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

pipeline рдореНрд╣рдгрдЬреЗ рдЬреЛрдбрдгреА: list | grep 3A | wc -l "3A рдордзреНрдпреЗ рдХрд┐рддреА" рдпрд╛рдЪреЗ рдЙрддреНрддрд░ рдПрдХрдореЗрдХрд╛рдВрдмрджреНрджрд▓ рдХрдзреАрдЪ рди рдРрдХрд▓реЗрд▓реНрдпрд╛ tools рдиреЗ рджреЗрддреЛ. рд╣реЗ рддреЗрд╡реНрд╣рд╛рдЪ рдЪрд╛рд▓рддреЗ рдЬреЗрд╡реНрд╣рд╛ stdout рд╡рд░ рдлрдХреНрдд data рдЕрд╕рддреЛ, рдореНрд╣рдгреВрдирдЪ log() stderr рд╡рд░ рдЬрд╛рддреЛ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

log() >&2 рдиреЗ рд╕рдВрдкрддреЛ. cmd_list { header; tail | filter | sort; } | column -t рдмрд╛рдВрдзрддреЛ. smoke test рдордзрд▓рд╛ L03 рджреЛрди рдХреЙрд░рд┐рдбреЙрд░ рд╡реЗрдЧрд│реЗ рджрд╛рдЦрд╡рддреЛ: 2>/dev/null log рд▓рдкрд╡рддреЛ, 2>&1 >/dev/null рдлрдХреНрдд log рдареЗрд╡рддреЛ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

bin/school.sh enrol Zoya 3B A > report.txt 2> log.txt; cat report.txt; echo ---; cat log.txt
bin/school.sh list | grep 3B | wc -l                   # a question, answered by three tools
bin/school.sh list 2>/dev/null | tee copy.txt | head -2 # tee: a copy on the way through
bin/school.sh enrol Bad 9Z 2>&1 >/dev/null              # only the complaint (note the order)
cat <<'EOF' | wc -l
one
two
EOF
bin/school.sh remove Zoya; rm -f report.txt log.txt copy.txt

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

report.txt рд░рд┐рдХрд╛рдореА рдЕрд╕рддреЗ рдЖрдгрд┐ log.txt рдордзреНрдпреЗ enrolled Zoya рдЕрд╕рддреЗ; enrol рдирдВрддрд░ pipeline 3 рдЫрд╛рдкрддреЗ (Meera, Rohan, Zoya); рдЪреБрдХреАрдЪреНрдпрд╛ enrol рдордзреНрдпреЗ рдлрдХреНрдд error рдЪреА рдУрд│ рджрд┐рд╕рддреЗ; here-doc 2 рдореЛрдЬрддреЛ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рддреБрдореНрд╣реА рддрд┐рдиреНрд╣реА streams рдкреИрдХреА рдкреНрд░рддреНрдпреЗрдХ рдХреБрдареЗрд╣реА рд╡рд│рд╡реВ рд╢рдХрддрд╛, рдЖрдгрд┐ script рдЪрд╛ log рддрд┐рдЪреНрдпрд╛ report рдкрд╛рд╕реВрди рджреВрд░ рдХрд╛ рдареЗрд╡рд╛рдпрдЪрд╛ рддреЗ рддреБрдореНрд╣рд╛рд▓рд╛ рдорд╛рд╣реАрдд рдЖрд╣реЗ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: CI stdout artifacts рдореНрд╣рдгреВрди рдЖрдгрд┐ stderr logs рдореНрд╣рдгреВрди capture рдХрд░рддреЗ; рджреЛрдиреНрд╣реА рдорд┐рд╕рд│рдгрд╛рд░реА script рдордзреНрдпреЗрдЪ "WARNING" рдЕрд╕рд▓реЗрд▓реЗ JSON рдмрдирд╡рддреЗ. рдкреНрд░рддреНрдпреЗрдХ pipeline step рдЪреНрдпрд╛ рдкрд╣рд┐рд▓реНрдпрд╛ рдУрд│реАрдд 2>&1 | tee build.log рдЕрд╕рддреЗ.

тПня╕П рдкреБрдвреЗ

рдзрдбрд╛ 04 тАФ text tools: grep, sed, awk рдЖрдгрд┐ рддреНрдпрд╛рдВрдЪреЗ рдорд┐рддреНрд░ рдиреЛрдВрджрд╡рд╣реАрддреВрди рдЙрддреНрддрд░реЗ рдХрд╛рдврддрд╛рдд.

ЁЯФА Lesson 03 тАФ Pipes & redirection: the corridors

ЁЯУН You are here: Lesson 03 of 12 ┬╖ Next: lesson-04-text-tools


ЁЯУж What's in this branch

Lessons 01тАУ03. The three streams every command has, and the plumbing that connects commands to each other and to files.

ЁЯзТ Explain like I'm 5

Every command has three corridors: one in (stdin, 0), one out for the report (stdout, 1), one for complaints (stderr, 2). A pipe | joins one command's out-corridor to the next one's in-corridor, so four small tools can answer one question. > sends the report into a file, >> adds to the end, 2> sends the complaints somewhere else. The rule that makes it all work: the report and the log never share a corridor.

ЁЯЧ║я╕П Diagram

flowchart LR
  K["тМия╕П stdin 0"] --> C["тЪЩя╕П command"]
  C -->|"1 stdout"| O["ЁЯУД report тЖТ | next ┬╖ > file ┬╖ >> file"]
  C -->|"2 stderr"| E["ЁЯУг log тЖТ 2> file ┬╖ 2>&1 ┬╖ 2>/dev/null"]

тЭУ What

ЁЯдФ Why

A pipeline is composition: list | grep 3A | wc -l answers "how many in 3A" with tools that never heard of each other. That only works if stdout carries data only, which is why log() goes to stderr.

ЁЯФз How (in this repo)

log() ends with >&2. cmd_list builds { header; tail | filter | sort; } | column -t. The smoke test's L03 shows the two corridors split: 2>/dev/null hides the log, 2>&1 >/dev/null keeps only the log.

ЁЯзк Try it

bin/school.sh enrol Zoya 3B A > report.txt 2> log.txt; cat report.txt; echo ---; cat log.txt
bin/school.sh list | grep 3B | wc -l                   # a question, answered by three tools
bin/school.sh list 2>/dev/null | tee copy.txt | head -2 # tee: a copy on the way through
bin/school.sh enrol Bad 9Z 2>&1 >/dev/null              # only the complaint (note the order)
cat <<'EOF' | wc -l
one
two
EOF
bin/school.sh remove Zoya; rm -f report.txt log.txt copy.txt

тЬЕ Verify тАФ what you should see

report.txt is empty and log.txt holds enrolled Zoya; the pipeline prints 3 after the enrol (Meera, Rohan, Zoya); the bad enrol shows only the error line; the here-doc counts 2.

ЁЯПБ What you just proved

You can route each of the three streams anywhere, and you know why a script's log must stay out of its report.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: CI captures stdout as artifacts and stderr as logs; a script that mixes them produces JSON with "WARNING" in the middle. 2>&1 | tee build.log is on the first line of every pipeline step.

тПня╕П Next

Lesson 04 тАФ the text tools: grep, sed, awk and friends turn the register into answers.

тЖР Previousfiles and pathsNext тЖТtext tools

This page is the lesson's README from the lesson-03-pipes-redirection branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.