[{"data":1,"prerenderedAt":2542},["ShallowReactive",2],{"page-\u002Flinux\u002F02-shell-and-command-line":3},{"id":4,"title":5,"body":6,"description":2535,"extension":2536,"meta":2537,"navigation":130,"path":2538,"seo":2539,"stem":2540,"__hash__":2541},"content\u002Flinux\u002F02-shell-and-command-line.md","02 — The Shell & Command Line",{"type":7,"value":8,"toc":2504},"minimark",[9,13,22,27,35,61,68,149,153,160,267,275,283,333,350,354,357,418,422,531,535,656,674,678,798,802,819,876,880,1009,1016,1025,1111,1115,1294,1298,1304,1394,1404,1408,1483,1490,1583,1587,1594,1604,1766,1773,1935,1941,2031,2035,2136,2140,2316,2320,2327,2350,2353,2500],[10,11,5],"h1",{"id":12},"_02-the-shell-command-line",[14,15,16,17,21],"p",{},"The shell reads commands, interprets them, and runs programs. On Linux, the default is ",[18,19,20],"strong",{},"Bash"," (GNU Bourne Again Shell). This chapter covers the shell as a production interface — redirection mechanics, pipeline concurrency, process lifecycle, and the gotchas that cause silent failures in scripts.",[23,24,26],"h2",{"id":25},"the-prompt","The Prompt",[14,28,29,30,34],{},"The default Bash prompt: ",[31,32,33],"code",{},"user@host:~$",".",[36,37,38,45,51],"ul",{},[39,40,41,44],"li",{},[31,42,43],{},"$"," — regular user prompt.",[39,46,47,50],{},[31,48,49],{},"#"," — root prompt (you're running as root).",[39,52,53,56,57,60],{},[31,54,55],{},"~"," — shorthand for your home directory (",[31,58,59],{},"$HOME",").",[14,62,63,64,67],{},"Customize via ",[31,65,66],{},"PS1",":",[69,70,72],"code-wrapper",{"language":71},"bash",[73,74,78],"pre",{"className":75,"code":76,"language":71,"meta":77,"style":77},"language-bash shiki shiki-themes github-light github-dark","# Complex Implementation: production-grade PS1 with exit-code awareness\n# — shows red prompt when last command failed, includes git branch, no color in pipes\nexport PS1='\\[\\033[0;32m\\]\\u@\\h\\[\\033[0m\\]:\\[\\033[0;34m\\]\\w\\[\\033[0m\\]'\n# \\u=user, \\h=host, \\w=cwd (with ~ for home)\n# \\[...\\] wraps non-printing chars (colors) so readline tracks cursor correctly\n\n# Exit-code-aware prompt (append to PS1):\nPROMPT_COMMAND='__rc=$?; if [ $__rc -ne 0 ]; then PS1=\"${PS1%\\\\$} [\\$?]\\\\$ \"; fi'\n","",[31,79,80,89,95,113,119,125,132,138],{"__ignoreMap":77},[81,82,85],"span",{"class":83,"line":84},"line",1,[81,86,88],{"class":87},"sdCPZ","# Complex Implementation: production-grade PS1 with exit-code awareness\n",[81,90,92],{"class":83,"line":91},2,[81,93,94],{"class":87},"# — shows red prompt when last command failed, includes git branch, no color in pipes\n",[81,96,98,102,106,109],{"class":83,"line":97},3,[81,99,101],{"class":100},"svdQ7","export",[81,103,105],{"class":104},"ssxIu"," PS1",[81,107,108],{"class":100},"=",[81,110,112],{"class":111},"sJ6F3","'\\[\\033[0;32m\\]\\u@\\h\\[\\033[0m\\]:\\[\\033[0;34m\\]\\w\\[\\033[0m\\]'\n",[81,114,116],{"class":83,"line":115},4,[81,117,118],{"class":87},"# \\u=user, \\h=host, \\w=cwd (with ~ for home)\n",[81,120,122],{"class":83,"line":121},5,[81,123,124],{"class":87},"# \\[...\\] wraps non-printing chars (colors) so readline tracks cursor correctly\n",[81,126,128],{"class":83,"line":127},6,[81,129,131],{"emptyLinePlaceholder":130},true,"\n",[81,133,135],{"class":83,"line":134},7,[81,136,137],{"class":87},"# Exit-code-aware prompt (append to PS1):\n",[81,139,141,144,146],{"class":83,"line":140},8,[81,142,143],{"class":104},"PROMPT_COMMAND",[81,145,108],{"class":100},[81,147,148],{"class":111},"'__rc=$?; if [ $__rc -ne 0 ]; then PS1=\"${PS1%\\\\$} [\\$?]\\\\$ \"; fi'\n",[23,150,152],{"id":151},"commands-arguments-options","Commands, Arguments, Options",[14,154,155,156,159],{},"A command line is split into ",[18,157,158],{},"words"," by whitespace:",[69,161,162],{"language":71},[73,163,165],{"className":75,"code":164,"language":71,"meta":77,"style":77},"$ ls -la \u002Fetc\n  └┘ └┘ └─┘\n   │  │   └ argument (the directory to list)\n   │  └ options (-l long, -a all — combined)\n   └ command (program name)\n",[31,166,167,182,193,222,252],{"__ignoreMap":77},[81,168,169,172,175,179],{"class":83,"line":84},[81,170,43],{"class":171},"sIsaT",[81,173,174],{"class":111}," ls",[81,176,178],{"class":177},"snvgF"," -la",[81,180,181],{"class":111}," \u002Fetc\n",[81,183,184,187,190],{"class":83,"line":91},[81,185,186],{"class":171},"  └┘",[81,188,189],{"class":111}," └┘",[81,191,192],{"class":111}," └─┘\n",[81,194,195,198,201,204,207,210,213,216,219],{"class":83,"line":97},[81,196,197],{"class":171},"   │",[81,199,200],{"class":111},"  │",[81,202,203],{"class":111},"   └",[81,205,206],{"class":111}," argument",[81,208,209],{"class":104}," (the ",[81,211,212],{"class":111},"directory",[81,214,215],{"class":111}," to",[81,217,218],{"class":111}," list",[81,220,221],{"class":104},")\n",[81,223,224,226,229,232,235,238,241,244,247,250],{"class":83,"line":115},[81,225,197],{"class":171},[81,227,228],{"class":111},"  └",[81,230,231],{"class":111}," options",[81,233,234],{"class":104}," (-l ",[81,236,237],{"class":111},"long,",[81,239,240],{"class":177}," -a",[81,242,243],{"class":111}," all",[81,245,246],{"class":111}," —",[81,248,249],{"class":111}," combined",[81,251,221],{"class":104},[81,253,254,256,259,262,265],{"class":83,"line":121},[81,255,203],{"class":171},[81,257,258],{"class":111}," command",[81,260,261],{"class":104}," (program ",[81,263,264],{"class":111},"name",[81,266,221],{"class":104},[268,269,271,274],"h3",{"id":270},"ends-options",[31,272,273],{},"--"," Ends Options",[14,276,277,279,280,67],{},[31,278,273],{}," tells the shell \"everything after this is an argument, not an option.\" Essential for filenames starting with ",[31,281,282],{},"-",[69,284,285],{"language":71},[73,286,288],{"className":75,"code":287,"language":71,"meta":77,"style":77},"rm -- -weirdfile          # remove a file named \"-weirdfile\"\ntouch -- --strangefile    # create a file named \"--strangefile\"\ngrep -- pattern --file    # search for \"pattern\" in a file named \"--file\"\n",[31,289,290,304,317],{"__ignoreMap":77},[81,291,292,295,298,301],{"class":83,"line":84},[81,293,294],{"class":171},"rm",[81,296,297],{"class":177}," --",[81,299,300],{"class":177}," -weirdfile",[81,302,303],{"class":87},"          # remove a file named \"-weirdfile\"\n",[81,305,306,309,311,314],{"class":83,"line":91},[81,307,308],{"class":171},"touch",[81,310,297],{"class":177},[81,312,313],{"class":177}," --strangefile",[81,315,316],{"class":87},"    # create a file named \"--strangefile\"\n",[81,318,319,322,324,327,330],{"class":83,"line":97},[81,320,321],{"class":171},"grep",[81,323,297],{"class":177},[81,325,326],{"class":111}," pattern",[81,328,329],{"class":177}," --file",[81,331,332],{"class":87},"    # search for \"pattern\" in a file named \"--file\"\n",[14,334,335,336,338,339,342,343,338,346,349],{},"Without ",[31,337,273],{},", ",[31,340,341],{},"rm -weirdfile"," treats ",[31,344,345],{},"-w",[31,347,348],{},"-e",", etc. as options and fails.",[23,351,353],{"id":352},"redirection","Redirection",[14,355,356],{},"Every process has standard streams:",[358,359,360,376],"table",{},[361,362,363],"thead",{},[364,365,366,370,373],"tr",{},[367,368,369],"th",{},"Stream",[367,371,372],{},"Number",[367,374,375],{},"Default",[377,378,379,393,406],"tbody",{},[364,380,381,387,390],{},[382,383,384],"td",{},[31,385,386],{},"stdin",[382,388,389],{},"0",[382,391,392],{},"keyboard",[364,394,395,400,403],{},[382,396,397],{},[31,398,399],{},"stdout",[382,401,402],{},"1",[382,404,405],{},"terminal",[364,407,408,413,416],{},[382,409,410],{},[31,411,412],{},"stderr",[382,414,415],{},"2",[382,417,405],{},[268,419,421],{"id":420},"redirect-output","Redirect Output",[69,423,424],{"language":71},[73,425,427],{"className":75,"code":426,"language":71,"meta":77,"style":77},"command > file           # stdout → file (overwrite)\ncommand >> file          # stdout → file (append)\ncommand 2> file          # stderr → file (overwrite)\ncommand 2>&1             # stderr → stdout (same destination)\ncommand > file 2>&1      # both stdout and stderr → file\ncommand &> file          # both → file (Bash 4+ shorthand)\ncommand > \u002Fdev\u002Fnull 2>&1 # discard all output\ncommand 2> \u002Fdev\u002Fnull     # discard only errors\n",[31,428,429,443,455,467,477,490,506,520],{"__ignoreMap":77},[81,430,431,434,437,440],{"class":83,"line":84},[81,432,433],{"class":177},"command",[81,435,436],{"class":100}," >",[81,438,439],{"class":111}," file",[81,441,442],{"class":87},"           # stdout → file (overwrite)\n",[81,444,445,447,450,452],{"class":83,"line":91},[81,446,433],{"class":177},[81,448,449],{"class":100}," >>",[81,451,439],{"class":111},[81,453,454],{"class":87},"          # stdout → file (append)\n",[81,456,457,459,462,464],{"class":83,"line":97},[81,458,433],{"class":177},[81,460,461],{"class":100}," 2>",[81,463,439],{"class":111},[81,465,466],{"class":87},"          # stderr → file (overwrite)\n",[81,468,469,471,474],{"class":83,"line":115},[81,470,433],{"class":177},[81,472,473],{"class":100}," 2>&1",[81,475,476],{"class":87},"             # stderr → stdout (same destination)\n",[81,478,479,481,483,485,487],{"class":83,"line":121},[81,480,433],{"class":177},[81,482,436],{"class":100},[81,484,439],{"class":111},[81,486,473],{"class":100},[81,488,489],{"class":87},"      # both stdout and stderr → file\n",[81,491,492,494,497,500,503],{"class":83,"line":127},[81,493,433],{"class":177},[81,495,496],{"class":104}," &",[81,498,499],{"class":100},">",[81,501,502],{"class":104}," file          ",[81,504,505],{"class":87},"# both → file (Bash 4+ shorthand)\n",[81,507,508,510,512,515,517],{"class":83,"line":134},[81,509,433],{"class":177},[81,511,436],{"class":100},[81,513,514],{"class":111}," \u002Fdev\u002Fnull",[81,516,473],{"class":100},[81,518,519],{"class":87}," # discard all output\n",[81,521,522,524,526,528],{"class":83,"line":140},[81,523,433],{"class":177},[81,525,461],{"class":100},[81,527,514],{"class":111},[81,529,530],{"class":87},"     # discard only errors\n",[268,532,534],{"id":533},"caveat-anti-pattern-redirection-order-matters","Caveat & Anti-Pattern: Redirection Order Matters",[69,536,537],{"language":71},[73,538,540],{"className":75,"code":539,"language":71,"meta":77,"style":77},"# NAIVE: stderr goes to terminal, stdout goes to \u002Fdev\u002Fnull\n# — redirections are processed LEFT to RIGHT\n# 2>&1 first: point stderr at where stdout CURRENTLY points (terminal)\n# > \u002Fdev\u002Fnull second: point stdout at \u002Fdev\u002Fnull\n# Result: stderr → terminal, stdout → \u002Fdev\u002Fnull (wrong if you wanted to discard errors)\ntar -czf \u002Fbackup\u002Fetc.tar.gz \u002Fetc 2>&1 > \u002Fdev\u002Fnull\n\n# PRODUCTION: redirect stdout BEFORE 2>&1\n# > \u002Fdev\u002Fnull first: stdout → \u002Fdev\u002Fnull\n# 2>&1 second: stderr → wherever stdout now points (\u002Fdev\u002Fnull)\n# Result: both → \u002Fdev\u002Fnull (correct)\ntar -czf \u002Fbackup\u002Fetc.tar.gz \u002Fetc > \u002Fdev\u002Fnull 2>&1\n# Or use the Bash 4+ shorthand:\ntar -czf \u002Fbackup\u002Fetc.tar.gz \u002Fetc &> \u002Fdev\u002Fnull\n",[31,541,542,547,552,557,562,567,588,592,597,603,609,615,633,639],{"__ignoreMap":77},[81,543,544],{"class":83,"line":84},[81,545,546],{"class":87},"# NAIVE: stderr goes to terminal, stdout goes to \u002Fdev\u002Fnull\n",[81,548,549],{"class":83,"line":91},[81,550,551],{"class":87},"# — redirections are processed LEFT to RIGHT\n",[81,553,554],{"class":83,"line":97},[81,555,556],{"class":87},"# 2>&1 first: point stderr at where stdout CURRENTLY points (terminal)\n",[81,558,559],{"class":83,"line":115},[81,560,561],{"class":87},"# > \u002Fdev\u002Fnull second: point stdout at \u002Fdev\u002Fnull\n",[81,563,564],{"class":83,"line":121},[81,565,566],{"class":87},"# Result: stderr → terminal, stdout → \u002Fdev\u002Fnull (wrong if you wanted to discard errors)\n",[81,568,569,572,575,578,581,583,585],{"class":83,"line":127},[81,570,571],{"class":171},"tar",[81,573,574],{"class":177}," -czf",[81,576,577],{"class":111}," \u002Fbackup\u002Fetc.tar.gz",[81,579,580],{"class":111}," \u002Fetc",[81,582,473],{"class":100},[81,584,436],{"class":100},[81,586,587],{"class":111}," \u002Fdev\u002Fnull\n",[81,589,590],{"class":83,"line":134},[81,591,131],{"emptyLinePlaceholder":130},[81,593,594],{"class":83,"line":140},[81,595,596],{"class":87},"# PRODUCTION: redirect stdout BEFORE 2>&1\n",[81,598,600],{"class":83,"line":599},9,[81,601,602],{"class":87},"# > \u002Fdev\u002Fnull first: stdout → \u002Fdev\u002Fnull\n",[81,604,606],{"class":83,"line":605},10,[81,607,608],{"class":87},"# 2>&1 second: stderr → wherever stdout now points (\u002Fdev\u002Fnull)\n",[81,610,612],{"class":83,"line":611},11,[81,613,614],{"class":87},"# Result: both → \u002Fdev\u002Fnull (correct)\n",[81,616,618,620,622,624,626,628,630],{"class":83,"line":617},12,[81,619,571],{"class":171},[81,621,574],{"class":177},[81,623,577],{"class":111},[81,625,580],{"class":111},[81,627,436],{"class":100},[81,629,514],{"class":111},[81,631,632],{"class":100}," 2>&1\n",[81,634,636],{"class":83,"line":635},13,[81,637,638],{"class":87},"# Or use the Bash 4+ shorthand:\n",[81,640,642,644,646,648,650,652,654],{"class":83,"line":641},14,[81,643,571],{"class":171},[81,645,574],{"class":177},[81,647,577],{"class":111},[81,649,580],{"class":111},[81,651,496],{"class":104},[81,653,499],{"class":100},[81,655,587],{"class":104},[14,657,658,659,665,666,668,669,673],{},"The rule: ",[18,660,661,662],{},"redirect stdout before ",[31,663,664],{},"2>&1",", because ",[31,667,664],{}," duplicates stdout's ",[670,671,672],"em",{},"current"," target.",[268,675,677],{"id":676},"here-documents-and-here-strings","Here-Documents and Here-Strings",[69,679,680],{"language":71},[73,681,683],{"className":75,"code":682,"language":71,"meta":77,"style":77},"# Complex Implementation: generate a config file with variable interpolation\n# — here-doc with unquoted delimiter allows expansion; quoted prevents it\ncat \u003C\u003CEOF > \u002Ftmp\u002Fconfig.conf\nhost = $HOSTNAME                    # expanded (unquoted EOF)\nport = 8080\nuser = ${USER}\nEOF\n\n# Prevent expansion (literal content):\ncat \u003C\u003C'EOF' > \u002Ftmp\u002Fno-expand.conf\nhome = $HOME                        # literal $HOME (quoted 'EOF')\nEOF\n\n# Here-string: feed a string into stdin\ngrep \"root\" \u003C\u003C\u003C \"root:x:0:0:root:\u002Froot:\u002Fbin\u002Fbash\"\n",[31,684,685,690,695,711,722,727,738,743,747,752,766,771,775,779,784],{"__ignoreMap":77},[81,686,687],{"class":83,"line":84},[81,688,689],{"class":87},"# Complex Implementation: generate a config file with variable interpolation\n",[81,691,692],{"class":83,"line":91},[81,693,694],{"class":87},"# — here-doc with unquoted delimiter allows expansion; quoted prevents it\n",[81,696,697,700,703,706,708],{"class":83,"line":97},[81,698,699],{"class":171},"cat",[81,701,702],{"class":100}," \u003C\u003C",[81,704,705],{"class":111},"EOF",[81,707,436],{"class":100},[81,709,710],{"class":111}," \u002Ftmp\u002Fconfig.conf\n",[81,712,713,716,719],{"class":83,"line":115},[81,714,715],{"class":111},"host = ",[81,717,718],{"class":104},"$HOSTNAME",[81,720,721],{"class":111},"                    # expanded (unquoted EOF)\n",[81,723,724],{"class":83,"line":121},[81,725,726],{"class":111},"port = 8080\n",[81,728,729,732,735],{"class":83,"line":127},[81,730,731],{"class":111},"user = ${",[81,733,734],{"class":104},"USER",[81,736,737],{"class":111},"}\n",[81,739,740],{"class":83,"line":134},[81,741,742],{"class":111},"EOF\n",[81,744,745],{"class":83,"line":140},[81,746,131],{"emptyLinePlaceholder":130},[81,748,749],{"class":83,"line":599},[81,750,751],{"class":87},"# Prevent expansion (literal content):\n",[81,753,754,756,758,761,763],{"class":83,"line":605},[81,755,699],{"class":171},[81,757,702],{"class":100},[81,759,760],{"class":111},"'EOF'",[81,762,436],{"class":100},[81,764,765],{"class":111}," \u002Ftmp\u002Fno-expand.conf\n",[81,767,768],{"class":83,"line":611},[81,769,770],{"class":111},"home = $HOME                        # literal $HOME (quoted 'EOF')\n",[81,772,773],{"class":83,"line":617},[81,774,742],{"class":111},[81,776,777],{"class":83,"line":635},[81,778,131],{"emptyLinePlaceholder":130},[81,780,781],{"class":83,"line":641},[81,782,783],{"class":87},"# Here-string: feed a string into stdin\n",[81,785,787,789,792,795],{"class":83,"line":786},15,[81,788,321],{"class":171},[81,790,791],{"class":111}," \"root\"",[81,793,794],{"class":100}," \u003C\u003C\u003C",[81,796,797],{"class":111}," \"root:x:0:0:root:\u002Froot:\u002Fbin\u002Fbash\"\n",[23,799,801],{"id":800},"pipes","Pipes",[14,803,804,805,808,809,811,812,814,815,818],{},"A pipe (",[31,806,807],{},"|",") connects one command's ",[31,810,399],{}," to another's ",[31,813,386],{},". Each command in a pipeline runs ",[18,816,817],{},"concurrently"," (a separate process):",[69,820,821],{"language":71},[73,822,824],{"className":75,"code":823,"language":71,"meta":77,"style":77},"# Complex Implementation: frequency-count the top 10 IPs in an access log\n# — each stage runs concurrently; data streams through the pipe\nawk '{print $1}' \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log | sort | uniq -c | sort -rn | head -10\n",[31,825,826,831,836],{"__ignoreMap":77},[81,827,828],{"class":83,"line":84},[81,829,830],{"class":87},"# Complex Implementation: frequency-count the top 10 IPs in an access log\n",[81,832,833],{"class":83,"line":91},[81,834,835],{"class":87},"# — each stage runs concurrently; data streams through the pipe\n",[81,837,838,841,844,847,850,853,855,858,861,863,865,868,870,873],{"class":83,"line":97},[81,839,840],{"class":171},"awk",[81,842,843],{"class":111}," '{print $1}'",[81,845,846],{"class":111}," \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log",[81,848,849],{"class":100}," |",[81,851,852],{"class":171}," sort",[81,854,849],{"class":100},[81,856,857],{"class":171}," uniq",[81,859,860],{"class":177}," -c",[81,862,849],{"class":100},[81,864,852],{"class":171},[81,866,867],{"class":177}," -rn",[81,869,849],{"class":100},[81,871,872],{"class":171}," head",[81,874,875],{"class":177}," -10\n",[268,877,879],{"id":878},"edge-case-pipelines-hide-intermediate-failures","Edge Case: Pipelines Hide Intermediate Failures",[69,881,882],{"language":71},[73,883,885],{"className":75,"code":884,"language":71,"meta":77,"style":77},"# NAIVE: if grep finds no match, it exits 1 — but the pipeline exits 0 (wc's status)\ngrep \"error\" \u002Fvar\u002Flog\u002Fsyslog | wc -l\n# echo $? → 0 (wc succeeded, even if grep found nothing)\n\n# PRODUCTION: set -o pipefail makes the pipeline exit on ANY stage failure\nset -o pipefail\ngrep \"error\" \u002Fvar\u002Flog\u002Fsyslog | wc -l\n# echo $? → 1 (grep failed, pipeline fails)\n\n# Or check PIPESTATUS array (Bash):\ngrep \"error\" \u002Fvar\u002Flog\u002Fsyslog | wc -l\necho \"grep exit: ${PIPESTATUS[0]}\"  # 1 if no match\necho \"wc exit:   ${PIPESTATUS[1]}\"  # 0\n",[31,886,887,892,910,915,919,924,935,949,954,958,963,977,994],{"__ignoreMap":77},[81,888,889],{"class":83,"line":84},[81,890,891],{"class":87},"# NAIVE: if grep finds no match, it exits 1 — but the pipeline exits 0 (wc's status)\n",[81,893,894,896,899,902,904,907],{"class":83,"line":91},[81,895,321],{"class":171},[81,897,898],{"class":111}," \"error\"",[81,900,901],{"class":111}," \u002Fvar\u002Flog\u002Fsyslog",[81,903,849],{"class":100},[81,905,906],{"class":171}," wc",[81,908,909],{"class":177}," -l\n",[81,911,912],{"class":83,"line":97},[81,913,914],{"class":87},"# echo $? → 0 (wc succeeded, even if grep found nothing)\n",[81,916,917],{"class":83,"line":115},[81,918,131],{"emptyLinePlaceholder":130},[81,920,921],{"class":83,"line":121},[81,922,923],{"class":87},"# PRODUCTION: set -o pipefail makes the pipeline exit on ANY stage failure\n",[81,925,926,929,932],{"class":83,"line":127},[81,927,928],{"class":177},"set",[81,930,931],{"class":177}," -o",[81,933,934],{"class":111}," pipefail\n",[81,936,937,939,941,943,945,947],{"class":83,"line":134},[81,938,321],{"class":171},[81,940,898],{"class":111},[81,942,901],{"class":111},[81,944,849],{"class":100},[81,946,906],{"class":171},[81,948,909],{"class":177},[81,950,951],{"class":83,"line":140},[81,952,953],{"class":87},"# echo $? → 1 (grep failed, pipeline fails)\n",[81,955,956],{"class":83,"line":599},[81,957,131],{"emptyLinePlaceholder":130},[81,959,960],{"class":83,"line":605},[81,961,962],{"class":87},"# Or check PIPESTATUS array (Bash):\n",[81,964,965,967,969,971,973,975],{"class":83,"line":611},[81,966,321],{"class":171},[81,968,898],{"class":111},[81,970,901],{"class":111},[81,972,849],{"class":100},[81,974,906],{"class":171},[81,976,909],{"class":177},[81,978,979,982,985,988,991],{"class":83,"line":617},[81,980,981],{"class":177},"echo",[81,983,984],{"class":111}," \"grep exit: ${",[81,986,987],{"class":104},"PIPESTATUS",[81,989,990],{"class":111},"[0]}\"",[81,992,993],{"class":87},"  # 1 if no match\n",[81,995,996,998,1001,1003,1006],{"class":83,"line":635},[81,997,981],{"class":177},[81,999,1000],{"class":111}," \"wc exit:   ${",[81,1002,987],{"class":104},[81,1004,1005],{"class":111},"[1]}\"",[81,1007,1008],{"class":87},"  # 0\n",[268,1010,1012,1015],{"id":1011},"tee-split-a-stream",[31,1013,1014],{},"tee"," — Split a Stream",[14,1017,1018,1020,1021,1024],{},[31,1019,1014],{}," writes stdin to a file ",[670,1022,1023],{},"and"," passes it to stdout — like a T-junction:",[69,1026,1027],{"language":71},[73,1028,1030],{"className":75,"code":1029,"language":71,"meta":77,"style":77},"# Complex Implementation: capture output to a file AND pipe to grep simultaneously\n# — tee needs sudo when writing to root-owned paths (the redirect itself runs as you)\ndmesg | tee dmesg-full.log | grep -i error > dmesg-errors.log\n\n# Writing to a root-owned file via redirect fails (redirect runs as YOU, not root):\n# NAIVE: sudo echo \"config\" > \u002Fetc\u002Fmyapp.conf    → Permission denied (the > is yours)\n# PRODUCTION:\necho \"config\" | sudo tee \u002Fetc\u002Fmyapp.conf > \u002Fdev\u002Fnull\n",[31,1031,1032,1037,1042,1071,1075,1080,1085,1090],{"__ignoreMap":77},[81,1033,1034],{"class":83,"line":84},[81,1035,1036],{"class":87},"# Complex Implementation: capture output to a file AND pipe to grep simultaneously\n",[81,1038,1039],{"class":83,"line":91},[81,1040,1041],{"class":87},"# — tee needs sudo when writing to root-owned paths (the redirect itself runs as you)\n",[81,1043,1044,1047,1049,1052,1055,1057,1060,1063,1066,1068],{"class":83,"line":97},[81,1045,1046],{"class":171},"dmesg",[81,1048,849],{"class":100},[81,1050,1051],{"class":171}," tee",[81,1053,1054],{"class":111}," dmesg-full.log",[81,1056,849],{"class":100},[81,1058,1059],{"class":171}," grep",[81,1061,1062],{"class":177}," -i",[81,1064,1065],{"class":111}," error",[81,1067,436],{"class":100},[81,1069,1070],{"class":111}," dmesg-errors.log\n",[81,1072,1073],{"class":83,"line":115},[81,1074,131],{"emptyLinePlaceholder":130},[81,1076,1077],{"class":83,"line":121},[81,1078,1079],{"class":87},"# Writing to a root-owned file via redirect fails (redirect runs as YOU, not root):\n",[81,1081,1082],{"class":83,"line":127},[81,1083,1084],{"class":87},"# NAIVE: sudo echo \"config\" > \u002Fetc\u002Fmyapp.conf    → Permission denied (the > is yours)\n",[81,1086,1087],{"class":83,"line":134},[81,1088,1089],{"class":87},"# PRODUCTION:\n",[81,1091,1092,1094,1097,1099,1102,1104,1107,1109],{"class":83,"line":140},[81,1093,981],{"class":177},[81,1095,1096],{"class":111}," \"config\"",[81,1098,849],{"class":100},[81,1100,1101],{"class":171}," sudo",[81,1103,1051],{"class":111},[81,1105,1106],{"class":111}," \u002Fetc\u002Fmyapp.conf",[81,1108,436],{"class":100},[81,1110,587],{"class":111},[23,1112,1114],{"id":1113},"job-control","Job Control",[69,1116,1117],{"language":71},[73,1118,1120],{"className":75,"code":1119,"language":71,"meta":77,"style":77},"# Complex Implementation: parallel background jobs with wait + exit-code capture\n# — launch 3 jobs, wait for all, report failures\nset -e\njob1 & pid1=$!\njob2 & pid2=$!\njob3 & pid3=$!\n\n# Wait for each and check exit codes\nwait $pid1 || echo \"job1 failed with $?\"\nwait $pid2 || echo \"job2 failed with $?\"\nwait $pid3 || echo \"job3 failed with $?\"\n\n# Disown to survive logout:\nlong-task & disown\n# Or use nohup (immune to SIGHUP):\nnohup long-task > task.log 2>&1 &\n# Best: tmux\u002Fscreen (reattachable)\n",[31,1121,1122,1127,1132,1139,1152,1164,1176,1180,1185,1208,1226,1244,1248,1253,1264,1269,1288],{"__ignoreMap":77},[81,1123,1124],{"class":83,"line":84},[81,1125,1126],{"class":87},"# Complex Implementation: parallel background jobs with wait + exit-code capture\n",[81,1128,1129],{"class":83,"line":91},[81,1130,1131],{"class":87},"# — launch 3 jobs, wait for all, report failures\n",[81,1133,1134,1136],{"class":83,"line":97},[81,1135,928],{"class":177},[81,1137,1138],{"class":177}," -e\n",[81,1140,1141,1144,1147,1149],{"class":83,"line":115},[81,1142,1143],{"class":171},"job1",[81,1145,1146],{"class":104}," & pid1",[81,1148,108],{"class":100},[81,1150,1151],{"class":177},"$!\n",[81,1153,1154,1157,1160,1162],{"class":83,"line":121},[81,1155,1156],{"class":171},"job2",[81,1158,1159],{"class":104}," & pid2",[81,1161,108],{"class":100},[81,1163,1151],{"class":177},[81,1165,1166,1169,1172,1174],{"class":83,"line":127},[81,1167,1168],{"class":171},"job3",[81,1170,1171],{"class":104}," & pid3",[81,1173,108],{"class":100},[81,1175,1151],{"class":177},[81,1177,1178],{"class":83,"line":134},[81,1179,131],{"emptyLinePlaceholder":130},[81,1181,1182],{"class":83,"line":140},[81,1183,1184],{"class":87},"# Wait for each and check exit codes\n",[81,1186,1187,1190,1193,1196,1199,1202,1205],{"class":83,"line":599},[81,1188,1189],{"class":177},"wait",[81,1191,1192],{"class":104}," $pid1 ",[81,1194,1195],{"class":100},"||",[81,1197,1198],{"class":177}," echo",[81,1200,1201],{"class":111}," \"job1 failed with ",[81,1203,1204],{"class":177},"$?",[81,1206,1207],{"class":111},"\"\n",[81,1209,1210,1212,1215,1217,1219,1222,1224],{"class":83,"line":605},[81,1211,1189],{"class":177},[81,1213,1214],{"class":104}," $pid2 ",[81,1216,1195],{"class":100},[81,1218,1198],{"class":177},[81,1220,1221],{"class":111}," \"job2 failed with ",[81,1223,1204],{"class":177},[81,1225,1207],{"class":111},[81,1227,1228,1230,1233,1235,1237,1240,1242],{"class":83,"line":611},[81,1229,1189],{"class":177},[81,1231,1232],{"class":104}," $pid3 ",[81,1234,1195],{"class":100},[81,1236,1198],{"class":177},[81,1238,1239],{"class":111}," \"job3 failed with ",[81,1241,1204],{"class":177},[81,1243,1207],{"class":111},[81,1245,1246],{"class":83,"line":617},[81,1247,131],{"emptyLinePlaceholder":130},[81,1249,1250],{"class":83,"line":635},[81,1251,1252],{"class":87},"# Disown to survive logout:\n",[81,1254,1255,1258,1261],{"class":83,"line":641},[81,1256,1257],{"class":171},"long-task",[81,1259,1260],{"class":104}," & ",[81,1262,1263],{"class":177},"disown\n",[81,1265,1266],{"class":83,"line":786},[81,1267,1268],{"class":87},"# Or use nohup (immune to SIGHUP):\n",[81,1270,1272,1275,1278,1280,1283,1285],{"class":83,"line":1271},16,[81,1273,1274],{"class":171},"nohup",[81,1276,1277],{"class":111}," long-task",[81,1279,436],{"class":100},[81,1281,1282],{"class":111}," task.log",[81,1284,473],{"class":100},[81,1286,1287],{"class":104}," &\n",[81,1289,1291],{"class":83,"line":1290},17,[81,1292,1293],{"class":87},"# Best: tmux\u002Fscreen (reattachable)\n",[23,1295,1297],{"id":1296},"command-substitution","Command Substitution",[14,1299,1300,1303],{},[31,1301,1302],{},"$(...)"," runs a command and inserts its output:",[69,1305,1306],{"language":71},[73,1307,1309],{"className":75,"code":1308,"language":71,"meta":77,"style":77},"echo \"Today is $(date +%A)\"\ncd \"$(dirname \"$(realpath script.sh)\")\"   # go to script's directory (nested $())\nfiles=$(ls \u002Fetc\u002F*.conf)                    # capture output in a variable\nkill $(pidof nginx)                        # kill all nginx PIDs\n",[31,1310,1311,1324,1346,1374],{"__ignoreMap":77},[81,1312,1313,1315,1318,1321],{"class":83,"line":84},[81,1314,981],{"class":177},[81,1316,1317],{"class":111}," \"Today is $(",[81,1319,1320],{"class":171},"date",[81,1322,1323],{"class":111}," +%A)\"\n",[81,1325,1326,1329,1332,1335,1337,1340,1343],{"class":83,"line":91},[81,1327,1328],{"class":177},"cd",[81,1330,1331],{"class":111}," \"$(",[81,1333,1334],{"class":171},"dirname",[81,1336,1331],{"class":111},[81,1338,1339],{"class":171},"realpath",[81,1341,1342],{"class":111}," script.sh)\")\"",[81,1344,1345],{"class":87},"   # go to script's directory (nested $())\n",[81,1347,1348,1351,1353,1356,1359,1362,1365,1368,1371],{"class":83,"line":97},[81,1349,1350],{"class":104},"files",[81,1352,108],{"class":100},[81,1354,1355],{"class":104},"$(",[81,1357,1358],{"class":171},"ls",[81,1360,1361],{"class":111}," \u002Fetc\u002F",[81,1363,1364],{"class":177},"*",[81,1366,1367],{"class":111},".conf",[81,1369,1370],{"class":104},")                    ",[81,1372,1373],{"class":87},"# capture output in a variable\n",[81,1375,1376,1379,1382,1385,1388,1391],{"class":83,"line":115},[81,1377,1378],{"class":177},"kill",[81,1380,1381],{"class":104}," $(",[81,1383,1384],{"class":171},"pidof",[81,1386,1387],{"class":111}," nginx",[81,1389,1390],{"class":104},")                        ",[81,1392,1393],{"class":87},"# kill all nginx PIDs\n",[14,1395,1396,1397,1399,1400,1403],{},"Prefer ",[31,1398,1302],{}," over backticks ",[31,1401,1402],{},"`...`"," — backticks can't nest cleanly and are deprecated.",[23,1405,1407],{"id":1406},"environment-variables","Environment Variables",[69,1409,1410],{"language":71},[73,1411,1413],{"className":75,"code":1412,"language":71,"meta":77,"style":77},"FOO=\"bar\"              # shell variable (not exported — children don't see it)\nexport FOO             # now exported → child processes inherit it\nexport BAR=\"baz\"       # set and export in one step\nenv                    # show all environment variables\nprintenv PATH          # show one variable\nunset FOO              # delete a variable\n",[31,1414,1415,1428,1438,1453,1461,1472],{"__ignoreMap":77},[81,1416,1417,1420,1422,1425],{"class":83,"line":84},[81,1418,1419],{"class":104},"FOO",[81,1421,108],{"class":100},[81,1423,1424],{"class":111},"\"bar\"",[81,1426,1427],{"class":87},"              # shell variable (not exported — children don't see it)\n",[81,1429,1430,1432,1435],{"class":83,"line":91},[81,1431,101],{"class":100},[81,1433,1434],{"class":104}," FOO             ",[81,1436,1437],{"class":87},"# now exported → child processes inherit it\n",[81,1439,1440,1442,1445,1447,1450],{"class":83,"line":97},[81,1441,101],{"class":100},[81,1443,1444],{"class":104}," BAR",[81,1446,108],{"class":100},[81,1448,1449],{"class":111},"\"baz\"",[81,1451,1452],{"class":87},"       # set and export in one step\n",[81,1454,1455,1458],{"class":83,"line":115},[81,1456,1457],{"class":171},"env",[81,1459,1460],{"class":87},"                    # show all environment variables\n",[81,1462,1463,1466,1469],{"class":83,"line":121},[81,1464,1465],{"class":171},"printenv",[81,1467,1468],{"class":111}," PATH",[81,1470,1471],{"class":87},"          # show one variable\n",[81,1473,1474,1477,1480],{"class":83,"line":127},[81,1475,1476],{"class":177},"unset",[81,1478,1479],{"class":111}," FOO",[81,1481,1482],{"class":87},"              # delete a variable\n",[268,1484,1486,1489],{"id":1485},"path-how-commands-are-found",[31,1487,1488],{},"PATH"," — How Commands Are Found",[69,1491,1492],{"language":71},[73,1493,1495],{"className":75,"code":1494,"language":71,"meta":77,"style":77},"# Complex Implementation: understand the shell's command resolution order\n# 1. Shell builtins (cd, echo, export) — checked first\n# 2. Functions and aliases — checked next\n# 3. Hash table (cached path lookups) — checked next\n# 4. $PATH directories — searched left to right\n\ntype ls            # shows: alias, builtin, function, or binary path\nwhich ls           # \u002Fusr\u002Fbin\u002Fls — full path of the first match (external only)\nhash               # shell's cache of command → path mappings\nhash -r            # clear the hash cache (if you install a new binary in a higher-priority dir)\n\n# Anti-Pattern: putting . (current dir) in PATH\n# export PATH=.:$PATH   → if someone puts a malicious `ls` in \u002Ftmp, you run it\n# Never put . in PATH (historical Unix vulnerability)\n",[31,1496,1497,1502,1507,1512,1517,1522,1526,1536,1546,1554,1564,1568,1573,1578],{"__ignoreMap":77},[81,1498,1499],{"class":83,"line":84},[81,1500,1501],{"class":87},"# Complex Implementation: understand the shell's command resolution order\n",[81,1503,1504],{"class":83,"line":91},[81,1505,1506],{"class":87},"# 1. Shell builtins (cd, echo, export) — checked first\n",[81,1508,1509],{"class":83,"line":97},[81,1510,1511],{"class":87},"# 2. Functions and aliases — checked next\n",[81,1513,1514],{"class":83,"line":115},[81,1515,1516],{"class":87},"# 3. Hash table (cached path lookups) — checked next\n",[81,1518,1519],{"class":83,"line":121},[81,1520,1521],{"class":87},"# 4. $PATH directories — searched left to right\n",[81,1523,1524],{"class":83,"line":127},[81,1525,131],{"emptyLinePlaceholder":130},[81,1527,1528,1531,1533],{"class":83,"line":134},[81,1529,1530],{"class":177},"type",[81,1532,174],{"class":111},[81,1534,1535],{"class":87},"            # shows: alias, builtin, function, or binary path\n",[81,1537,1538,1541,1543],{"class":83,"line":140},[81,1539,1540],{"class":177},"which",[81,1542,174],{"class":111},[81,1544,1545],{"class":87},"           # \u002Fusr\u002Fbin\u002Fls — full path of the first match (external only)\n",[81,1547,1548,1551],{"class":83,"line":599},[81,1549,1550],{"class":177},"hash",[81,1552,1553],{"class":87},"               # shell's cache of command → path mappings\n",[81,1555,1556,1558,1561],{"class":83,"line":605},[81,1557,1550],{"class":177},[81,1559,1560],{"class":177}," -r",[81,1562,1563],{"class":87},"            # clear the hash cache (if you install a new binary in a higher-priority dir)\n",[81,1565,1566],{"class":83,"line":611},[81,1567,131],{"emptyLinePlaceholder":130},[81,1569,1570],{"class":83,"line":617},[81,1571,1572],{"class":87},"# Anti-Pattern: putting . (current dir) in PATH\n",[81,1574,1575],{"class":83,"line":635},[81,1576,1577],{"class":87},"# export PATH=.:$PATH   → if someone puts a malicious `ls` in \u002Ftmp, you run it\n",[81,1579,1580],{"class":83,"line":641},[81,1581,1582],{"class":87},"# Never put . in PATH (historical Unix vulnerability)\n",[23,1584,1586],{"id":1585},"exit-status","Exit Status",[14,1588,1589,1590,1593],{},"Every command returns an ",[18,1591,1592],{},"exit status"," (0–255) to the shell:",[36,1595,1596,1601],{},[39,1597,1598,1600],{},[31,1599,389],{}," — success.",[39,1602,1603],{},"non-zero — failure (the specific code is command-specific; 1, 2, 126, 127 are common).",[69,1605,1606],{"language":71},[73,1607,1609],{"className":75,"code":1608,"language":71,"meta":77,"style":77},"# Complex Implementation: idiomatic conditional execution with && and ||\nmkdir -p \u002Ftmp\u002Fwork && cd \u002Ftmp\u002Fwork      # cd only if mkdir succeeds\ntest -f \u002Fetc\u002Fpasswd && echo \"exists\" || echo \"missing\"\nping -c1 -W1 8.8.8.8 >\u002Fdev\u002Fnull && echo \"up\" || echo \"down\"\n\n# Edge case: $? is overwritten by the NEXT command\n# NAIVE:\ncmd; echo \"status: $?\"; ls       # by the time you check, ls may have reset $?\n# PRODUCTION:\ncmd; status=$?; echo \"status: $status\"; ls\n",[31,1610,1611,1616,1637,1663,1696,1700,1705,1710,1735,1739],{"__ignoreMap":77},[81,1612,1613],{"class":83,"line":84},[81,1614,1615],{"class":87},"# Complex Implementation: idiomatic conditional execution with && and ||\n",[81,1617,1618,1621,1624,1627,1630,1632,1634],{"class":83,"line":91},[81,1619,1620],{"class":171},"mkdir",[81,1622,1623],{"class":177}," -p",[81,1625,1626],{"class":111}," \u002Ftmp\u002Fwork",[81,1628,1629],{"class":104}," && ",[81,1631,1328],{"class":177},[81,1633,1626],{"class":111},[81,1635,1636],{"class":87},"      # cd only if mkdir succeeds\n",[81,1638,1639,1642,1645,1648,1650,1652,1655,1658,1660],{"class":83,"line":97},[81,1640,1641],{"class":177},"test",[81,1643,1644],{"class":177}," -f",[81,1646,1647],{"class":111}," \u002Fetc\u002Fpasswd",[81,1649,1629],{"class":104},[81,1651,981],{"class":177},[81,1653,1654],{"class":111}," \"exists\"",[81,1656,1657],{"class":100}," ||",[81,1659,1198],{"class":177},[81,1661,1662],{"class":111}," \"missing\"\n",[81,1664,1665,1668,1671,1674,1677,1679,1682,1684,1686,1689,1691,1693],{"class":83,"line":115},[81,1666,1667],{"class":171},"ping",[81,1669,1670],{"class":177}," -c1",[81,1672,1673],{"class":177}," -W1",[81,1675,1676],{"class":177}," 8.8.8.8",[81,1678,436],{"class":100},[81,1680,1681],{"class":111},"\u002Fdev\u002Fnull",[81,1683,1629],{"class":104},[81,1685,981],{"class":177},[81,1687,1688],{"class":111}," \"up\"",[81,1690,1657],{"class":100},[81,1692,1198],{"class":177},[81,1694,1695],{"class":111}," \"down\"\n",[81,1697,1698],{"class":83,"line":121},[81,1699,131],{"emptyLinePlaceholder":130},[81,1701,1702],{"class":83,"line":127},[81,1703,1704],{"class":87},"# Edge case: $? is overwritten by the NEXT command\n",[81,1706,1707],{"class":83,"line":134},[81,1708,1709],{"class":87},"# NAIVE:\n",[81,1711,1712,1715,1718,1720,1723,1725,1728,1730,1732],{"class":83,"line":140},[81,1713,1714],{"class":171},"cmd",[81,1716,1717],{"class":104},"; ",[81,1719,981],{"class":177},[81,1721,1722],{"class":111}," \"status: ",[81,1724,1204],{"class":177},[81,1726,1727],{"class":111},"\"",[81,1729,1717],{"class":104},[81,1731,1358],{"class":171},[81,1733,1734],{"class":87},"       # by the time you check, ls may have reset $?\n",[81,1736,1737],{"class":83,"line":599},[81,1738,1089],{"class":87},[81,1740,1741,1743,1746,1748,1750,1752,1754,1756,1759,1761,1763],{"class":83,"line":605},[81,1742,1714],{"class":171},[81,1744,1745],{"class":104},"; status",[81,1747,108],{"class":100},[81,1749,1204],{"class":177},[81,1751,1717],{"class":104},[81,1753,981],{"class":177},[81,1755,1722],{"class":111},[81,1757,1758],{"class":104},"$status",[81,1760,1727],{"class":111},[81,1762,1717],{"class":104},[81,1764,1765],{"class":171},"ls\n",[23,1767,1769,1772],{"id":1768},"find-locating-files",[31,1770,1771],{},"find"," — Locating Files",[69,1774,1775],{"language":71},[73,1776,1778],{"className":75,"code":1777,"language":71,"meta":77,"style":77},"# Complex Implementation: find + exec with null-delimited safety\n# — handles filenames with spaces, newlines, and quotes\nfind \u002Fvar\u002Flog -type f -name \"*.log\" -print0 | xargs -0 grep \"error\"\n\n# Prefer -exec {} + (batches files into fewer invocations, null-safe):\nfind \u002Fvar\u002Flog -type f -name \"*.log\" -exec grep \"error\" {} +\n\n# Time-based search (modified in last 24h):\nfind \u002Ftmp -mtime -1\n# Size-based (larger than 100 MB):\nfind \u002F -size +100M -type f 2>\u002Fdev\u002Fnull\n# Permission-based (setuid root — security audit):\nfind \u002F -perm -4000 -type f 2>\u002Fdev\u002Fnull\n",[31,1779,1780,1785,1790,1825,1829,1834,1861,1865,1870,1883,1888,1910,1915],{"__ignoreMap":77},[81,1781,1782],{"class":83,"line":84},[81,1783,1784],{"class":87},"# Complex Implementation: find + exec with null-delimited safety\n",[81,1786,1787],{"class":83,"line":91},[81,1788,1789],{"class":87},"# — handles filenames with spaces, newlines, and quotes\n",[81,1791,1792,1794,1797,1800,1803,1806,1809,1812,1814,1817,1820,1822],{"class":83,"line":97},[81,1793,1771],{"class":171},[81,1795,1796],{"class":111}," \u002Fvar\u002Flog",[81,1798,1799],{"class":177}," -type",[81,1801,1802],{"class":111}," f",[81,1804,1805],{"class":177}," -name",[81,1807,1808],{"class":111}," \"*.log\"",[81,1810,1811],{"class":177}," -print0",[81,1813,849],{"class":100},[81,1815,1816],{"class":171}," xargs",[81,1818,1819],{"class":177}," -0",[81,1821,1059],{"class":111},[81,1823,1824],{"class":111}," \"error\"\n",[81,1826,1827],{"class":83,"line":115},[81,1828,131],{"emptyLinePlaceholder":130},[81,1830,1831],{"class":83,"line":121},[81,1832,1833],{"class":87},"# Prefer -exec {} + (batches files into fewer invocations, null-safe):\n",[81,1835,1836,1838,1840,1842,1844,1846,1848,1851,1853,1855,1858],{"class":83,"line":127},[81,1837,1771],{"class":171},[81,1839,1796],{"class":111},[81,1841,1799],{"class":177},[81,1843,1802],{"class":111},[81,1845,1805],{"class":177},[81,1847,1808],{"class":111},[81,1849,1850],{"class":177}," -exec",[81,1852,1059],{"class":111},[81,1854,898],{"class":111},[81,1856,1857],{"class":111}," {}",[81,1859,1860],{"class":111}," +\n",[81,1862,1863],{"class":83,"line":134},[81,1864,131],{"emptyLinePlaceholder":130},[81,1866,1867],{"class":83,"line":140},[81,1868,1869],{"class":87},"# Time-based search (modified in last 24h):\n",[81,1871,1872,1874,1877,1880],{"class":83,"line":599},[81,1873,1771],{"class":171},[81,1875,1876],{"class":111}," \u002Ftmp",[81,1878,1879],{"class":177}," -mtime",[81,1881,1882],{"class":177}," -1\n",[81,1884,1885],{"class":83,"line":605},[81,1886,1887],{"class":87},"# Size-based (larger than 100 MB):\n",[81,1889,1890,1892,1895,1898,1901,1903,1905,1907],{"class":83,"line":611},[81,1891,1771],{"class":171},[81,1893,1894],{"class":111}," \u002F",[81,1896,1897],{"class":177}," -size",[81,1899,1900],{"class":111}," +100M",[81,1902,1799],{"class":177},[81,1904,1802],{"class":111},[81,1906,461],{"class":100},[81,1908,1909],{"class":111},"\u002Fdev\u002Fnull\n",[81,1911,1912],{"class":83,"line":617},[81,1913,1914],{"class":87},"# Permission-based (setuid root — security audit):\n",[81,1916,1917,1919,1921,1924,1927,1929,1931,1933],{"class":83,"line":635},[81,1918,1771],{"class":171},[81,1920,1894],{"class":111},[81,1922,1923],{"class":177}," -perm",[81,1925,1926],{"class":177}," -4000",[81,1928,1799],{"class":177},[81,1930,1802],{"class":111},[81,1932,461],{"class":100},[81,1934,1909],{"class":111},[23,1936,1938,1940],{"id":1937},"tar-archives",[31,1939,571],{}," — Archives",[69,1942,1943],{"language":71},[73,1944,1946],{"className":75,"code":1945,"language":71,"meta":77,"style":77},"# Complex Implementation: stream a tar over SSH (no intermediate file)\n# — pipe through SSH, extract on the remote side\ntar -czf - \u002Fetc | ssh backup-server \"tar -xzf - -C \u002Fbackup\"\n\n# Exclude patterns:\ntar --exclude=\"*.log\" --exclude=\"node_modules\" -czf app.tar.gz \u002Fapp\n\n# Edge Case: tar strips leading \u002F by default (safety feature)\n# tar -czf backup.tar.gz \u002Fetc → stores \"etc\u002F...\" (no leading \u002F)\n# This prevents extracting to \u002F on a different machine and overwriting system files\n",[31,1947,1948,1953,1958,1980,1984,1989,2012,2016,2021,2026],{"__ignoreMap":77},[81,1949,1950],{"class":83,"line":84},[81,1951,1952],{"class":87},"# Complex Implementation: stream a tar over SSH (no intermediate file)\n",[81,1954,1955],{"class":83,"line":91},[81,1956,1957],{"class":87},"# — pipe through SSH, extract on the remote side\n",[81,1959,1960,1962,1964,1967,1969,1971,1974,1977],{"class":83,"line":97},[81,1961,571],{"class":171},[81,1963,574],{"class":177},[81,1965,1966],{"class":111}," -",[81,1968,580],{"class":111},[81,1970,849],{"class":100},[81,1972,1973],{"class":171}," ssh",[81,1975,1976],{"class":111}," backup-server",[81,1978,1979],{"class":111}," \"tar -xzf - -C \u002Fbackup\"\n",[81,1981,1982],{"class":83,"line":115},[81,1983,131],{"emptyLinePlaceholder":130},[81,1985,1986],{"class":83,"line":121},[81,1987,1988],{"class":87},"# Exclude patterns:\n",[81,1990,1991,1993,1996,1999,2001,2004,2006,2009],{"class":83,"line":127},[81,1992,571],{"class":171},[81,1994,1995],{"class":177}," --exclude=",[81,1997,1998],{"class":111},"\"*.log\"",[81,2000,1995],{"class":177},[81,2002,2003],{"class":111},"\"node_modules\"",[81,2005,574],{"class":177},[81,2007,2008],{"class":111}," app.tar.gz",[81,2010,2011],{"class":111}," \u002Fapp\n",[81,2013,2014],{"class":83,"line":134},[81,2015,131],{"emptyLinePlaceholder":130},[81,2017,2018],{"class":83,"line":140},[81,2019,2020],{"class":87},"# Edge Case: tar strips leading \u002F by default (safety feature)\n",[81,2022,2023],{"class":83,"line":599},[81,2024,2025],{"class":87},"# tar -czf backup.tar.gz \u002Fetc → stores \"etc\u002F...\" (no leading \u002F)\n",[81,2027,2028],{"class":83,"line":605},[81,2029,2030],{"class":87},"# This prevents extracting to \u002F on a different machine and overwriting system files\n",[23,2032,2034],{"id":2033},"tips-tricks","💡 Tips & Tricks",[36,2036,2037,2051,2071,2098,2123],{},[39,2038,2039,2042,2043,2046,2047,2050],{},[18,2040,2041],{},"Idiom",": use ",[31,2044,2045],{},"mkdir -p"," (create parent dirs, no error if exists) — ",[31,2048,2049],{},"mkdir -p \u002Fa\u002Fb\u002Fc"," creates the whole chain.",[39,2052,2053,2042,2055,2058,2059,2062,2063,2066,2067,2070],{},[18,2054,2041],{},[31,2056,2057],{},"tail -F"," (capital) instead of ",[31,2060,2061],{},"tail -f"," for log watching — ",[31,2064,2065],{},"-F"," handles log rotation (re-opens if the file is moved\u002Frecreated). ",[31,2068,2069],{},"-f"," stops following if the file is moved.",[39,2072,2073,2042,2075,2078,2079,2082,2083,2085,2086,2089,2090,2093,2094,2097],{},[18,2074,2041],{},[31,2076,2077],{},"head -n 20"," \u002F ",[31,2080,2081],{},"tail -n 20"," to peek at large files — never ",[31,2084,699],{}," a 10 GB log. ",[31,2087,2088],{},"less"," for interactive paging (press ",[31,2091,2092],{},"q"," to quit, ",[31,2095,2096],{},"\u002F"," to search).",[39,2099,2100,2103,2104,2107,2108,2111,2112,2115,2116,2119,2120,34],{},[18,2101,2102],{},"Performance",": ",[31,2105,2106],{},"find ... -exec {} +"," is faster than ",[31,2109,2110],{},"-exec {} \\;"," — ",[31,2113,2114],{},"+"," batches files into fewer command invocations. ",[31,2117,2118],{},"xargs -0"," is also fast and safe with ",[31,2121,2122],{},"-print0",[39,2124,2125,2103,2128,2131,2132,2135],{},[18,2126,2127],{},"Debug",[31,2129,2130],{},"set -x"," in a script prints each command before running it — shows how the shell expands variables and globs. ",[31,2133,2134],{},"set +x"," turns it off.",[23,2137,2139],{"id":2138},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[36,2141,2142,2181,2209,2232,2271,2296],{},[39,2143,2144,2150,2151,2154,2155,2158,2159,2162,2163,2166,2167,2169,2170,2173,2174,2176,2177,2180],{},[18,2145,2146,2149],{},[31,2147,2148],{},"rm -rf \u002F"," is real",": a typo like ",[31,2152,2153],{},"rm -rf $VAR\u002F*"," with ",[31,2156,2157],{},"VAR"," unset expands to ",[31,2160,2161],{},"rm -rf \u002F*",". Always ",[31,2164,2165],{},"set -u"," (error on unset variables) in scripts. GNU ",[31,2168,294],{}," has ",[31,2171,2172],{},"--preserve-root"," (default) that refuses ",[31,2175,2148],{},", but ",[31,2178,2179],{},"\u002F*"," bypasses it.",[39,2182,2183,2103,2189,2192,2193,2196,2197,2200,2201,2204,2205,2208],{},[18,2184,2185,2188],{},[31,2186,2187],{},"cp"," silently overwrites",[31,2190,2191],{},"cp bigfile existing"," replaces ",[31,2194,2195],{},"existing"," with no warning. Use ",[31,2198,2199],{},"cp -n"," (no-clobber) or ",[31,2202,2203],{},"cp -i"," (interactive) for safety. ",[31,2206,2207],{},"cp -a"," preserves attributes and is the go-to for backups.",[39,2210,2211,2217,2218,2220,2221,2224,2225,2228,2229,2231],{},[18,2212,2213,2216],{},[31,2214,2215],{},"mv"," across filesystems is a copy + delete",": within one filesystem, ",[31,2219,2215],{}," is instant (just renames the inode entry). Across filesystems (e.g., ",[31,2222,2223],{},"\u002Fhome"," → ",[31,2226,2227],{},"\u002Fmnt\u002Fusb","), ",[31,2230,2215],{}," copies then deletes — slow for large files, and it fails mid-way if out of space.",[39,2233,2234,2103,2237,2240,2241,2244,2245,2248,2249,2252,2253,2256,2257,2259,2260,2263,2264,2266,2267,2270],{},[18,2235,2236],{},"Globs don't match hidden files by default",[31,2238,2239],{},"ls *"," doesn't show ",[31,2242,2243],{},".bashrc",". Use ",[31,2246,2247],{},"ls -a"," or ",[31,2250,2251],{},"ls .*"," explicitly. ",[31,2254,2255],{},".*"," also matches ",[31,2258,34],{}," and ",[31,2261,2262],{},".."," (dangerous with ",[31,2265,294],{},"); use ",[31,2268,2269],{},"rm .[^.]*"," to avoid them.",[39,2272,2273,2103,2276,2279,2280,2283,2284,2287,2288,2291,2292,2295],{},[18,2274,2275],{},"Pipelines run concurrently, not sequentially",[31,2277,2278],{},"cmd1 | cmd2"," starts both at once — ",[31,2281,2282],{},"cmd2"," can process ",[31,2285,2286],{},"cmd1","'s output as it streams. This is why ",[31,2289,2290],{},"yes | head -10"," works without ",[31,2293,2294],{},"yes"," running forever (head closes the pipe, yes gets SIGPIPE).",[39,2297,2298,2103,2303,2306,2307,2309,2310,2312,2313,34],{},[18,2299,2300,2302],{},[31,2301,1204],{}," is overwritten by the next command",[31,2304,2305],{},"cmd; echo \"status: $?\"; ls"," — by the time you check, ",[31,2308,1358],{}," may have reset ",[31,2311,1204],{},". Capture immediately: ",[31,2314,2315],{},"cmd; status=$?; ...",[23,2317,2319],{"id":2318},"spot-the-bug","🧠 Spot the Bug",[14,2321,2322,2323,2326],{},"A sysadmin wants to back up ",[31,2324,2325],{},"\u002Fetc"," to a file and discard errors, but this command does nothing useful:",[69,2328,2329],{"language":71},[73,2330,2332],{"className":75,"code":2331,"language":71,"meta":77,"style":77},"tar -czf \u002Fbackup\u002Fetc.tar.gz \u002Fetc 2>&1 > \u002Fdev\u002Fnull\n",[31,2333,2334],{"__ignoreMap":77},[81,2335,2336,2338,2340,2342,2344,2346,2348],{"class":83,"line":84},[81,2337,571],{"class":171},[81,2339,574],{"class":177},[81,2341,577],{"class":111},[81,2343,580],{"class":111},[81,2345,473],{"class":100},[81,2347,436],{"class":100},[81,2349,587],{"class":111},[14,2351,2352],{},"What's wrong, and how do you fix it?",[2354,2355,2356,2360,2369,2397,2419,2422,2485],"details",{},[2357,2358,2359],"summary",{},"Answer",[14,2361,2362,2365,2366,67],{},[18,2363,2364],{},"Order of redirections matters."," Redirections are processed ",[18,2367,2368],{},"left to right",[2370,2371,2372,2387],"ol",{},[39,2373,2374,2376,2377,2379,2380,2382,2383,2386],{},[31,2375,664],{}," — point ",[31,2378,412],{}," at where ",[31,2381,399],{}," ",[670,2384,2385],{},"currently"," points (the terminal).",[39,2388,2389,2376,2392,2394,2395,34],{},[31,2390,2391],{},"> \u002Fdev\u002Fnull",[31,2393,399],{}," at ",[31,2396,1681],{},[14,2398,2399,2400,2402,2403,2382,2406,2408,2409,2411,2412,2414,2415,2418],{},"So ",[31,2401,412],{}," ends up at the terminal (it was redirected ",[670,2404,2405],{},"before",[31,2407,399],{}," changed), and ",[31,2410,399],{}," goes to ",[31,2413,1681],{},". The result: you see errors on the terminal, and the archive's normal output (none, but the principle) is discarded. The archive is still created — but the intent was to discard ",[670,2416,2417],{},"errors",", and that failed.",[14,2420,2421],{},"To discard both stdout and stderr (or just stderr), the correct order is:",[69,2423,2424],{"language":71},[73,2425,2427],{"className":75,"code":2426,"language":71,"meta":77,"style":77},"tar -czf \u002Fbackup\u002Fetc.tar.gz \u002Fetc > \u002Fdev\u002Fnull 2>&1   # both → \u002Fdev\u002Fnull\ntar -czf \u002Fbackup\u002Fetc.tar.gz \u002Fetc 2> \u002Fdev\u002Fnull       # only stderr → \u002Fdev\u002Fnull\ntar -czf \u002Fbackup\u002Fetc.tar.gz \u002Fetc &> \u002Fdev\u002Fnull       # Bash 4+ shorthand for both\n",[31,2428,2429,2448,2465],{"__ignoreMap":77},[81,2430,2431,2433,2435,2437,2439,2441,2443,2445],{"class":83,"line":84},[81,2432,571],{"class":171},[81,2434,574],{"class":177},[81,2436,577],{"class":111},[81,2438,580],{"class":111},[81,2440,436],{"class":100},[81,2442,514],{"class":111},[81,2444,473],{"class":100},[81,2446,2447],{"class":87},"   # both → \u002Fdev\u002Fnull\n",[81,2449,2450,2452,2454,2456,2458,2460,2462],{"class":83,"line":91},[81,2451,571],{"class":171},[81,2453,574],{"class":177},[81,2455,577],{"class":111},[81,2457,580],{"class":111},[81,2459,461],{"class":100},[81,2461,514],{"class":111},[81,2463,2464],{"class":87},"       # only stderr → \u002Fdev\u002Fnull\n",[81,2466,2467,2469,2471,2473,2475,2477,2479,2482],{"class":83,"line":97},[81,2468,571],{"class":171},[81,2470,574],{"class":177},[81,2472,577],{"class":111},[81,2474,580],{"class":111},[81,2476,496],{"class":104},[81,2478,499],{"class":100},[81,2480,2481],{"class":104}," \u002Fdev\u002Fnull       ",[81,2483,2484],{"class":87},"# Bash 4+ shorthand for both\n",[14,2486,658,2487,665,2491,668,2493,2495,2496,2499],{},[18,2488,661,2489],{},[31,2490,664],{},[31,2492,664],{},[670,2494,672],{}," target. ",[31,2497,2498],{},"&> file"," (Bash 4+) does both in one shot and is clearest.",[2501,2502,2503],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}",{"title":77,"searchDepth":91,"depth":91,"links":2505},[2506,2507,2511,2516,2521,2522,2523,2527,2528,2530,2532,2533,2534],{"id":25,"depth":91,"text":26},{"id":151,"depth":91,"text":152,"children":2508},[2509],{"id":270,"depth":97,"text":2510},"-- Ends Options",{"id":352,"depth":91,"text":353,"children":2512},[2513,2514,2515],{"id":420,"depth":97,"text":421},{"id":533,"depth":97,"text":534},{"id":676,"depth":97,"text":677},{"id":800,"depth":91,"text":801,"children":2517},[2518,2519],{"id":878,"depth":97,"text":879},{"id":1011,"depth":97,"text":2520},"tee — Split a Stream",{"id":1113,"depth":91,"text":1114},{"id":1296,"depth":91,"text":1297},{"id":1406,"depth":91,"text":1407,"children":2524},[2525],{"id":1485,"depth":97,"text":2526},"PATH — How Commands Are Found",{"id":1585,"depth":91,"text":1586},{"id":1768,"depth":91,"text":2529},"find — Locating Files",{"id":1937,"depth":91,"text":2531},"tar — Archives",{"id":2033,"depth":91,"text":2034},{"id":2138,"depth":91,"text":2139},{"id":2318,"depth":91,"text":2319},"The shell reads commands, interprets them, and runs programs. On Linux, the default is Bash (GNU Bourne Again Shell). This chapter covers the shell as a production interface — redirection mechanics, pipeline concurrency, process lifecycle, and the gotchas that cause silent failures in scripts.","md",{},"\u002Flinux\u002F02-shell-and-command-line",{"title":5,"description":2535},"linux\u002F02-shell-and-command-line","qzvkeGtzDPTYjojmS-ekO5GgQM_cP3_SuEqxq5RCtOc",1789924649762]