[{"data":1,"prerenderedAt":5349},["ShallowReactive",2],{"page-\u002Fbash\u002F04-control-flow":3},{"id":4,"title":5,"body":6,"description":5342,"extension":5343,"meta":5344,"navigation":55,"path":5345,"seo":5346,"stem":5347,"__hash__":5348},"content\u002Fbash\u002F04-control-flow.md","Bash 04 — Control Flow Internals, Loop Patterns & Exit Status Mechanics",{"type":7,"value":8,"toc":5316},"minimark",[9,14,23,437,448,775,782,1302,1312,1558,1565,2076,2083,2220,2224,2501,2508,3204,3212,3515,3522,3840,3844,4179,4183,4431,4435,4858,4862,5165,5169,5173,5216,5312],[10,11,13],"h1",{"id":12},"_04-control-flow-internals-loop-patterns-exit-status-mechanics","04 — Control Flow Internals, Loop Patterns & Exit Status Mechanics",[15,16,18,22],"h2",{"id":17},"if-its-all-about-exit-status",[19,20,21],"code",{},"if",": It's All About Exit Status",[24,25,27],"code-wrapper",{"language":26},"bash",[28,29,33],"pre",{"className":30,"code":31,"language":26,"meta":32,"style":32},"language-bash shiki shiki-themes github-light github-dark","# ── if runs the `then` block if the command's exit status is 0 (success) ──\n# ANY command works — not just [[ ]] or [ ]:\n\nif grep -q \"error\" logfile.txt; then        # grep -q: exit 0 if match, 1 if no match, 2 on error\n    echo \"found errors\"                    # runs if grep exits 0\nfi\n\nif cd \"$dir\" 2>\u002Fdev\u002Fnull; then              # cd: exit 0 if dir exists, non-zero otherwise\n    echo \"now in $dir\"                      # 2>\u002Fdev\u002Fnull suppresses \"No such file\" error\nfi\n\nif ping -c 1 -W 2 \"$host\" &>\u002Fdev\u002Fnull; then # ping: exit 0 if host responds\n    echo \"host is up\"\nfi\n\nif command -v docker &>\u002Fdev\u002Fnull; then      # command -v: exit 0 if command exists\n    echo \"docker available\"\nfi\n\n# ── elif chains ──\nif [[ $status -eq 200 ]]; then\n    echo \"OK\"\nelif [[ $status -ge 400 && $status -lt 500 ]]; then\n    echo \"client error\"\nelif [[ $status -ge 500 ]]; then\n    echo \"server error\"\nelse\n    echo \"unknown: $status\"\nfi\n\n# ── Negating a condition ──\nif ! grep -q \"ok\" file.txt; then            # ! negates the exit status\n    echo \"no ok found\"\nfi\n","",[19,34,35,44,50,57,88,100,106,111,141,156,161,166,207,215,220,225,250,258,263,268,274,294,302,332,340,355,363,369,383,388,393,399,424,432],{"__ignoreMap":32},[36,37,40],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"sdCPZ","# ── if runs the `then` block if the command's exit status is 0 (success) ──\n",[36,45,47],{"class":38,"line":46},2,[36,48,49],{"class":42},"# ANY command works — not just [[ ]] or [ ]:\n",[36,51,53],{"class":38,"line":52},3,[36,54,56],{"emptyLinePlaceholder":55},true,"\n",[36,58,60,63,67,71,75,78,82,85],{"class":38,"line":59},4,[36,61,21],{"class":62},"svdQ7",[36,64,66],{"class":65},"sIsaT"," grep",[36,68,70],{"class":69},"snvgF"," -q",[36,72,74],{"class":73},"sJ6F3"," \"error\"",[36,76,77],{"class":73}," logfile.txt",[36,79,81],{"class":80},"ssxIu","; ",[36,83,84],{"class":62},"then",[36,86,87],{"class":42},"        # grep -q: exit 0 if match, 1 if no match, 2 on error\n",[36,89,91,94,97],{"class":38,"line":90},5,[36,92,93],{"class":69},"    echo",[36,95,96],{"class":73}," \"found errors\"",[36,98,99],{"class":42},"                    # runs if grep exits 0\n",[36,101,103],{"class":38,"line":102},6,[36,104,105],{"class":62},"fi\n",[36,107,109],{"class":38,"line":108},7,[36,110,56],{"emptyLinePlaceholder":55},[36,112,114,116,119,122,125,128,131,134,136,138],{"class":38,"line":113},8,[36,115,21],{"class":62},[36,117,118],{"class":69}," cd",[36,120,121],{"class":73}," \"",[36,123,124],{"class":80},"$dir",[36,126,127],{"class":73},"\"",[36,129,130],{"class":62}," 2>",[36,132,133],{"class":73},"\u002Fdev\u002Fnull",[36,135,81],{"class":80},[36,137,84],{"class":62},[36,139,140],{"class":42},"              # cd: exit 0 if dir exists, non-zero otherwise\n",[36,142,144,146,149,151,153],{"class":38,"line":143},9,[36,145,93],{"class":69},[36,147,148],{"class":73}," \"now in ",[36,150,124],{"class":80},[36,152,127],{"class":73},[36,154,155],{"class":42},"                      # 2>\u002Fdev\u002Fnull suppresses \"No such file\" error\n",[36,157,159],{"class":38,"line":158},10,[36,160,105],{"class":62},[36,162,164],{"class":38,"line":163},11,[36,165,56],{"emptyLinePlaceholder":55},[36,167,169,171,174,177,180,183,186,188,191,193,196,199,202,204],{"class":38,"line":168},12,[36,170,21],{"class":62},[36,172,173],{"class":65}," ping",[36,175,176],{"class":69}," -c",[36,178,179],{"class":69}," 1",[36,181,182],{"class":69}," -W",[36,184,185],{"class":69}," 2",[36,187,121],{"class":73},[36,189,190],{"class":80},"$host",[36,192,127],{"class":73},[36,194,195],{"class":80}," &",[36,197,198],{"class":62},">",[36,200,201],{"class":80},"\u002Fdev\u002Fnull; ",[36,203,84],{"class":62},[36,205,206],{"class":42}," # ping: exit 0 if host responds\n",[36,208,210,212],{"class":38,"line":209},13,[36,211,93],{"class":69},[36,213,214],{"class":73}," \"host is up\"\n",[36,216,218],{"class":38,"line":217},14,[36,219,105],{"class":62},[36,221,223],{"class":38,"line":222},15,[36,224,56],{"emptyLinePlaceholder":55},[36,226,228,230,233,236,239,241,243,245,247],{"class":38,"line":227},16,[36,229,21],{"class":62},[36,231,232],{"class":69}," command",[36,234,235],{"class":69}," -v",[36,237,238],{"class":73}," docker",[36,240,195],{"class":80},[36,242,198],{"class":62},[36,244,201],{"class":80},[36,246,84],{"class":62},[36,248,249],{"class":42},"      # command -v: exit 0 if command exists\n",[36,251,253,255],{"class":38,"line":252},17,[36,254,93],{"class":69},[36,256,257],{"class":73}," \"docker available\"\n",[36,259,261],{"class":38,"line":260},18,[36,262,105],{"class":62},[36,264,266],{"class":38,"line":265},19,[36,267,56],{"emptyLinePlaceholder":55},[36,269,271],{"class":38,"line":270},20,[36,272,273],{"class":42},"# ── elif chains ──\n",[36,275,277,279,282,285,288,291],{"class":38,"line":276},21,[36,278,21],{"class":62},[36,280,281],{"class":80}," [[ $status ",[36,283,284],{"class":62},"-eq",[36,286,287],{"class":69}," 200",[36,289,290],{"class":80}," ]]; ",[36,292,293],{"class":62},"then\n",[36,295,297,299],{"class":38,"line":296},22,[36,298,93],{"class":69},[36,300,301],{"class":73}," \"OK\"\n",[36,303,305,308,310,313,316,319,322,325,328,330],{"class":38,"line":304},23,[36,306,307],{"class":62},"elif",[36,309,281],{"class":80},[36,311,312],{"class":62},"-ge",[36,314,315],{"class":69}," 400",[36,317,318],{"class":62}," &&",[36,320,321],{"class":80}," $status ",[36,323,324],{"class":62},"-lt",[36,326,327],{"class":69}," 500",[36,329,290],{"class":80},[36,331,293],{"class":62},[36,333,335,337],{"class":38,"line":334},24,[36,336,93],{"class":69},[36,338,339],{"class":73}," \"client error\"\n",[36,341,343,345,347,349,351,353],{"class":38,"line":342},25,[36,344,307],{"class":62},[36,346,281],{"class":80},[36,348,312],{"class":62},[36,350,327],{"class":69},[36,352,290],{"class":80},[36,354,293],{"class":62},[36,356,358,360],{"class":38,"line":357},26,[36,359,93],{"class":69},[36,361,362],{"class":73}," \"server error\"\n",[36,364,366],{"class":38,"line":365},27,[36,367,368],{"class":62},"else\n",[36,370,372,374,377,380],{"class":38,"line":371},28,[36,373,93],{"class":69},[36,375,376],{"class":73}," \"unknown: ",[36,378,379],{"class":80},"$status",[36,381,382],{"class":73},"\"\n",[36,384,386],{"class":38,"line":385},29,[36,387,105],{"class":62},[36,389,391],{"class":38,"line":390},30,[36,392,56],{"emptyLinePlaceholder":55},[36,394,396],{"class":38,"line":395},31,[36,397,398],{"class":42},"# ── Negating a condition ──\n",[36,400,402,404,407,409,411,414,417,419,421],{"class":38,"line":401},32,[36,403,21],{"class":62},[36,405,406],{"class":62}," !",[36,408,66],{"class":65},[36,410,70],{"class":69},[36,412,413],{"class":73}," \"ok\"",[36,415,416],{"class":73}," file.txt",[36,418,81],{"class":80},[36,420,84],{"class":62},[36,422,423],{"class":42},"            # ! negates the exit status\n",[36,425,427,429],{"class":38,"line":426},33,[36,428,93],{"class":69},[36,430,431],{"class":73}," \"no ok found\"\n",[36,433,435],{"class":38,"line":434},34,[36,436,105],{"class":62},[15,438,440,443,444,447],{"id":439},"short-circuit-composition",[19,441,442],{},"&&"," \u002F ",[19,445,446],{},"||",": Short-Circuit Composition",[24,449,450],{"language":26},[28,451,453],{"className":30,"code":452,"language":26,"meta":32,"style":32},"# ── && runs the right side ONLY if the left side succeeded ──\n# ── || runs the right side ONLY if the left side failed ──\n\n[[ -f config.txt ]] && echo \"config exists\"\n[[ -f config.txt ]] || { echo \"config missing\" >&2; exit 1; }\n\n# ── Chaining (all must succeed) ──\nmkdir -p \"$dir\" && cd \"$dir\" && touch marker.txt && echo \"setup complete\"\n\n# ── Guard pattern: check then act ──\n[[ -n \"$API_KEY\" ]] || { echo \"API_KEY required\" >&2; exit 1; }\n\n# ── Don't overuse — for complex logic, if\u002Fthen is clearer ──\n# ❌ HARD TO READ\n[[ $x -gt 0 ]] && [[ $y -gt 0 ]] && echo \"both positive\" || echo \"at least one non-positive\"\n# (the || binds to the LAST && — if the echo succeeds, || won't fire. Subtle!)\n\n# ✅ CLEAR\nif ((x > 0 && y > 0)); then\n    echo \"both positive\"\nelse\n    echo \"at least one non-positive\"\nfi\n\n# ── The || { ... } guard is a production idiom ──\ncd \"$BUILD_DIR\" || { echo \"can't cd to $BUILD_DIR\" >&2; exit 1; }\n# If cd fails, the || block runs: print error, exit. If cd succeeds, skip.\n# Note: use { } (command group, same shell) not ( ) (subshell — exit would only exit the subshell!)\n",[19,454,455,460,465,469,486,518,522,527,568,572,577,613,617,622,627,662,667,671,676,701,708,712,718,722,726,731,765,770],{"__ignoreMap":32},[36,456,457],{"class":38,"line":39},[36,458,459],{"class":42},"# ── && runs the right side ONLY if the left side succeeded ──\n",[36,461,462],{"class":38,"line":46},[36,463,464],{"class":42},"# ── || runs the right side ONLY if the left side failed ──\n",[36,466,467],{"class":38,"line":52},[36,468,56],{"emptyLinePlaceholder":55},[36,470,471,474,477,480,483],{"class":38,"line":59},[36,472,473],{"class":80},"[[ ",[36,475,476],{"class":62},"-f",[36,478,479],{"class":80}," config.txt ]] && ",[36,481,482],{"class":69},"echo",[36,484,485],{"class":73}," \"config exists\"\n",[36,487,488,490,492,495,497,500,502,505,508,510,513,515],{"class":38,"line":90},[36,489,473],{"class":80},[36,491,476],{"class":62},[36,493,494],{"class":80}," config.txt ]] ",[36,496,446],{"class":62},[36,498,499],{"class":80}," { ",[36,501,482],{"class":69},[36,503,504],{"class":73}," \"config missing\"",[36,506,507],{"class":62}," >&2",[36,509,81],{"class":80},[36,511,512],{"class":69},"exit",[36,514,179],{"class":69},[36,516,517],{"class":80},"; }\n",[36,519,520],{"class":38,"line":102},[36,521,56],{"emptyLinePlaceholder":55},[36,523,524],{"class":38,"line":108},[36,525,526],{"class":42},"# ── Chaining (all must succeed) ──\n",[36,528,529,532,535,537,539,541,544,547,549,551,553,555,558,561,563,565],{"class":38,"line":113},[36,530,531],{"class":65},"mkdir",[36,533,534],{"class":69}," -p",[36,536,121],{"class":73},[36,538,124],{"class":80},[36,540,127],{"class":73},[36,542,543],{"class":80}," && ",[36,545,546],{"class":69},"cd",[36,548,121],{"class":73},[36,550,124],{"class":80},[36,552,127],{"class":73},[36,554,543],{"class":80},[36,556,557],{"class":65},"touch",[36,559,560],{"class":73}," marker.txt",[36,562,543],{"class":80},[36,564,482],{"class":69},[36,566,567],{"class":73}," \"setup complete\"\n",[36,569,570],{"class":38,"line":143},[36,571,56],{"emptyLinePlaceholder":55},[36,573,574],{"class":38,"line":158},[36,575,576],{"class":42},"# ── Guard pattern: check then act ──\n",[36,578,579,581,584,586,589,591,594,596,598,600,603,605,607,609,611],{"class":38,"line":163},[36,580,473],{"class":80},[36,582,583],{"class":62},"-n",[36,585,121],{"class":73},[36,587,588],{"class":80},"$API_KEY",[36,590,127],{"class":73},[36,592,593],{"class":80}," ]] ",[36,595,446],{"class":62},[36,597,499],{"class":80},[36,599,482],{"class":69},[36,601,602],{"class":73}," \"API_KEY required\"",[36,604,507],{"class":62},[36,606,81],{"class":80},[36,608,512],{"class":69},[36,610,179],{"class":69},[36,612,517],{"class":80},[36,614,615],{"class":38,"line":168},[36,616,56],{"emptyLinePlaceholder":55},[36,618,619],{"class":38,"line":209},[36,620,621],{"class":42},"# ── Don't overuse — for complex logic, if\u002Fthen is clearer ──\n",[36,623,624],{"class":38,"line":217},[36,625,626],{"class":42},"# ❌ HARD TO READ\n",[36,628,629,632,635,638,641,643,645,648,650,653,656,659],{"class":38,"line":222},[36,630,631],{"class":80},"[[ $x ",[36,633,634],{"class":62},"-gt",[36,636,637],{"class":69}," 0",[36,639,640],{"class":80}," ]] && [[ $y ",[36,642,634],{"class":62},[36,644,637],{"class":69},[36,646,647],{"class":80}," ]] && ",[36,649,482],{"class":69},[36,651,652],{"class":73}," \"both positive\"",[36,654,655],{"class":62}," ||",[36,657,658],{"class":69}," echo",[36,660,661],{"class":73}," \"at least one non-positive\"\n",[36,663,664],{"class":38,"line":227},[36,665,666],{"class":42},"# (the || binds to the LAST && — if the echo succeeds, || won't fire. Subtle!)\n",[36,668,669],{"class":38,"line":252},[36,670,56],{"emptyLinePlaceholder":55},[36,672,673],{"class":38,"line":260},[36,674,675],{"class":42},"# ✅ CLEAR\n",[36,677,678,680,683,685,687,689,692,694,696,699],{"class":38,"line":265},[36,679,21],{"class":62},[36,681,682],{"class":80}," ((x ",[36,684,198],{"class":62},[36,686,637],{"class":69},[36,688,318],{"class":62},[36,690,691],{"class":80}," y ",[36,693,198],{"class":62},[36,695,637],{"class":69},[36,697,698],{"class":80},")); ",[36,700,293],{"class":62},[36,702,703,705],{"class":38,"line":270},[36,704,93],{"class":69},[36,706,707],{"class":73}," \"both positive\"\n",[36,709,710],{"class":38,"line":276},[36,711,368],{"class":62},[36,713,714,716],{"class":38,"line":296},[36,715,93],{"class":69},[36,717,661],{"class":73},[36,719,720],{"class":38,"line":304},[36,721,105],{"class":62},[36,723,724],{"class":38,"line":334},[36,725,56],{"emptyLinePlaceholder":55},[36,727,728],{"class":38,"line":342},[36,729,730],{"class":42},"# ── The || { ... } guard is a production idiom ──\n",[36,732,733,735,737,740,742,744,746,748,751,753,755,757,759,761,763],{"class":38,"line":357},[36,734,546],{"class":69},[36,736,121],{"class":73},[36,738,739],{"class":80},"$BUILD_DIR",[36,741,127],{"class":73},[36,743,655],{"class":62},[36,745,499],{"class":80},[36,747,482],{"class":69},[36,749,750],{"class":73}," \"can't cd to ",[36,752,739],{"class":80},[36,754,127],{"class":73},[36,756,507],{"class":62},[36,758,81],{"class":80},[36,760,512],{"class":69},[36,762,179],{"class":69},[36,764,517],{"class":80},[36,766,767],{"class":38,"line":365},[36,768,769],{"class":42},"# If cd fails, the || block runs: print error, exit. If cd succeeds, skip.\n",[36,771,772],{"class":38,"line":371},[36,773,774],{"class":42},"# Note: use { } (command group, same shell) not ( ) (subshell — exit would only exit the subshell!)\n",[15,776,778,781],{"id":777},"for-loops-list-and-c-style",[19,779,780],{},"for"," Loops: List and C-Style",[24,783,784],{"language":26},[28,785,787],{"className":30,"code":786,"language":26,"meta":32,"style":32},"# ── for list: iterate over words ──\nfor fruit in apple banana cherry; do\n    echo \"$fruit\"\ndone\n\n# ── for over a glob (safe — no word splitting issues) ──\nfor file in *.txt; do\n    echo \"processing $file\"\ndone\n# ⚠️ With nullglob off: if no .txt files, the loop runs ONCE with file=\"*.txt\" (literal).\n# Fix: shopt -s nullglob (empty result) or check inside:\nfor file in *.txt; do\n    [[ -e $file ]] || continue   # skip if no match (glob passed literally)\n    echo \"processing $file\"\ndone\n\n# ── for over array (ALWAYS quote [@]) ──\nfiles=(\"my file.txt\" \"other file.txt\" \"third.txt\")\nfor file in \"${files[@]}\"; do    # [@] quoted: each element is a separate word\n    echo \"$file\"\ndone\n\n# ── for over args ──\nfor arg in \"$@\"; do    # \"$@\" quoted: each positional arg is a separate word\n    echo \"arg: $arg\"\ndone\n\n# ── C-style for (arithmetic) ──\nfor ((i = 0; i \u003C 5; i++)); do\n    echo \"i=$i\"\ndone\n\n# ── C-style with multiple variables ──\nfor ((i = 0, j = 10; i \u003C 5; i++, j--)); do\n    printf '%d %d\\n' \"$i\" \"$j\"\ndone\n\n# ── C-style with step ──\nfor ((i = 0; i \u003C 100; i += 10)); do\n    echo \"i=$i\"   # 0 10 20 30 40 50 60 70 80 90\ndone\n\n# ── Infinite loop with break ──\nfor ((;;)); do\n    ((count++))\n    ((count >= 100)) && break\ndone\n",[19,788,789,794,818,829,834,838,843,859,871,875,880,885,899,918,928,932,936,941,964,994,1004,1008,1012,1017,1040,1052,1056,1060,1065,1095,1107,1111,1115,1120,1162,1184,1189,1194,1200,1229,1243,1248,1253,1259,1269,1280,1297],{"__ignoreMap":32},[36,790,791],{"class":38,"line":39},[36,792,793],{"class":42},"# ── for list: iterate over words ──\n",[36,795,796,798,801,804,807,810,813,815],{"class":38,"line":46},[36,797,780],{"class":62},[36,799,800],{"class":80}," fruit ",[36,802,803],{"class":62},"in",[36,805,806],{"class":73}," apple",[36,808,809],{"class":73}," banana",[36,811,812],{"class":73}," cherry",[36,814,81],{"class":80},[36,816,817],{"class":62},"do\n",[36,819,820,822,824,827],{"class":38,"line":52},[36,821,93],{"class":69},[36,823,121],{"class":73},[36,825,826],{"class":80},"$fruit",[36,828,382],{"class":73},[36,830,831],{"class":38,"line":59},[36,832,833],{"class":62},"done\n",[36,835,836],{"class":38,"line":90},[36,837,56],{"emptyLinePlaceholder":55},[36,839,840],{"class":38,"line":102},[36,841,842],{"class":42},"# ── for over a glob (safe — no word splitting issues) ──\n",[36,844,845,847,850,852,855,857],{"class":38,"line":108},[36,846,780],{"class":62},[36,848,849],{"class":80}," file ",[36,851,803],{"class":62},[36,853,854],{"class":73}," *.txt",[36,856,81],{"class":80},[36,858,817],{"class":62},[36,860,861,863,866,869],{"class":38,"line":113},[36,862,93],{"class":69},[36,864,865],{"class":73}," \"processing ",[36,867,868],{"class":80},"$file",[36,870,382],{"class":73},[36,872,873],{"class":38,"line":143},[36,874,833],{"class":62},[36,876,877],{"class":38,"line":158},[36,878,879],{"class":42},"# ⚠️ With nullglob off: if no .txt files, the loop runs ONCE with file=\"*.txt\" (literal).\n",[36,881,882],{"class":38,"line":163},[36,883,884],{"class":42},"# Fix: shopt -s nullglob (empty result) or check inside:\n",[36,886,887,889,891,893,895,897],{"class":38,"line":168},[36,888,780],{"class":62},[36,890,849],{"class":80},[36,892,803],{"class":62},[36,894,854],{"class":73},[36,896,81],{"class":80},[36,898,817],{"class":62},[36,900,901,904,907,910,912,915],{"class":38,"line":209},[36,902,903],{"class":80},"    [[ ",[36,905,906],{"class":62},"-e",[36,908,909],{"class":80}," $file ]] ",[36,911,446],{"class":62},[36,913,914],{"class":62}," continue",[36,916,917],{"class":42},"   # skip if no match (glob passed literally)\n",[36,919,920,922,924,926],{"class":38,"line":217},[36,921,93],{"class":69},[36,923,865],{"class":73},[36,925,868],{"class":80},[36,927,382],{"class":73},[36,929,930],{"class":38,"line":222},[36,931,833],{"class":62},[36,933,934],{"class":38,"line":227},[36,935,56],{"emptyLinePlaceholder":55},[36,937,938],{"class":38,"line":252},[36,939,940],{"class":42},"# ── for over array (ALWAYS quote [@]) ──\n",[36,942,943,946,949,952,955,958,961],{"class":38,"line":260},[36,944,945],{"class":80},"files",[36,947,948],{"class":62},"=",[36,950,951],{"class":80},"(",[36,953,954],{"class":73},"\"my file.txt\"",[36,956,957],{"class":73}," \"other file.txt\"",[36,959,960],{"class":73}," \"third.txt\"",[36,962,963],{"class":80},")\n",[36,965,966,968,970,972,975,977,980,983,986,988,991],{"class":38,"line":265},[36,967,780],{"class":62},[36,969,849],{"class":80},[36,971,803],{"class":62},[36,973,974],{"class":73}," \"${",[36,976,945],{"class":80},[36,978,979],{"class":73},"[",[36,981,982],{"class":62},"@",[36,984,985],{"class":73},"]}\"",[36,987,81],{"class":80},[36,989,990],{"class":62},"do",[36,992,993],{"class":42},"    # [@] quoted: each element is a separate word\n",[36,995,996,998,1000,1002],{"class":38,"line":270},[36,997,93],{"class":69},[36,999,121],{"class":73},[36,1001,868],{"class":80},[36,1003,382],{"class":73},[36,1005,1006],{"class":38,"line":276},[36,1007,833],{"class":62},[36,1009,1010],{"class":38,"line":296},[36,1011,56],{"emptyLinePlaceholder":55},[36,1013,1014],{"class":38,"line":304},[36,1015,1016],{"class":42},"# ── for over args ──\n",[36,1018,1019,1021,1024,1026,1028,1031,1033,1035,1037],{"class":38,"line":334},[36,1020,780],{"class":62},[36,1022,1023],{"class":80}," arg ",[36,1025,803],{"class":62},[36,1027,121],{"class":73},[36,1029,1030],{"class":69},"$@",[36,1032,127],{"class":73},[36,1034,81],{"class":80},[36,1036,990],{"class":62},[36,1038,1039],{"class":42},"    # \"$@\" quoted: each positional arg is a separate word\n",[36,1041,1042,1044,1047,1050],{"class":38,"line":342},[36,1043,93],{"class":69},[36,1045,1046],{"class":73}," \"arg: ",[36,1048,1049],{"class":80},"$arg",[36,1051,382],{"class":73},[36,1053,1054],{"class":38,"line":357},[36,1055,833],{"class":62},[36,1057,1058],{"class":38,"line":365},[36,1059,56],{"emptyLinePlaceholder":55},[36,1061,1062],{"class":38,"line":371},[36,1063,1064],{"class":42},"# ── C-style for (arithmetic) ──\n",[36,1066,1067,1069,1072,1074,1076,1079,1082,1085,1088,1091,1093],{"class":38,"line":385},[36,1068,780],{"class":62},[36,1070,1071],{"class":80}," ((i ",[36,1073,948],{"class":62},[36,1075,637],{"class":69},[36,1077,1078],{"class":80},"; i ",[36,1080,1081],{"class":62},"\u003C",[36,1083,1084],{"class":69}," 5",[36,1086,1087],{"class":80},"; i",[36,1089,1090],{"class":62},"++",[36,1092,698],{"class":80},[36,1094,817],{"class":62},[36,1096,1097,1099,1102,1105],{"class":38,"line":390},[36,1098,93],{"class":69},[36,1100,1101],{"class":73}," \"i=",[36,1103,1104],{"class":80},"$i",[36,1106,382],{"class":73},[36,1108,1109],{"class":38,"line":395},[36,1110,833],{"class":62},[36,1112,1113],{"class":38,"line":401},[36,1114,56],{"emptyLinePlaceholder":55},[36,1116,1117],{"class":38,"line":426},[36,1118,1119],{"class":42},"# ── C-style with multiple variables ──\n",[36,1121,1122,1124,1126,1128,1130,1133,1136,1138,1141,1143,1145,1147,1149,1152,1155,1158,1160],{"class":38,"line":434},[36,1123,780],{"class":62},[36,1125,1071],{"class":80},[36,1127,948],{"class":62},[36,1129,637],{"class":69},[36,1131,1132],{"class":62},",",[36,1134,1135],{"class":80}," j ",[36,1137,948],{"class":62},[36,1139,1140],{"class":69}," 10",[36,1142,1078],{"class":80},[36,1144,1081],{"class":62},[36,1146,1084],{"class":69},[36,1148,1087],{"class":80},[36,1150,1151],{"class":62},"++,",[36,1153,1154],{"class":80}," j",[36,1156,1157],{"class":62},"--",[36,1159,698],{"class":80},[36,1161,817],{"class":62},[36,1163,1165,1168,1171,1173,1175,1177,1179,1182],{"class":38,"line":1164},35,[36,1166,1167],{"class":69},"    printf",[36,1169,1170],{"class":73}," '%d %d\\n'",[36,1172,121],{"class":73},[36,1174,1104],{"class":80},[36,1176,127],{"class":73},[36,1178,121],{"class":73},[36,1180,1181],{"class":80},"$j",[36,1183,382],{"class":73},[36,1185,1187],{"class":38,"line":1186},36,[36,1188,833],{"class":62},[36,1190,1192],{"class":38,"line":1191},37,[36,1193,56],{"emptyLinePlaceholder":55},[36,1195,1197],{"class":38,"line":1196},38,[36,1198,1199],{"class":42},"# ── C-style with step ──\n",[36,1201,1203,1205,1207,1209,1211,1213,1215,1218,1220,1223,1225,1227],{"class":38,"line":1202},39,[36,1204,780],{"class":62},[36,1206,1071],{"class":80},[36,1208,948],{"class":62},[36,1210,637],{"class":69},[36,1212,1078],{"class":80},[36,1214,1081],{"class":62},[36,1216,1217],{"class":69}," 100",[36,1219,1078],{"class":80},[36,1221,1222],{"class":62},"+=",[36,1224,1140],{"class":69},[36,1226,698],{"class":80},[36,1228,817],{"class":62},[36,1230,1232,1234,1236,1238,1240],{"class":38,"line":1231},40,[36,1233,93],{"class":69},[36,1235,1101],{"class":73},[36,1237,1104],{"class":80},[36,1239,127],{"class":73},[36,1241,1242],{"class":42},"   # 0 10 20 30 40 50 60 70 80 90\n",[36,1244,1246],{"class":38,"line":1245},41,[36,1247,833],{"class":62},[36,1249,1251],{"class":38,"line":1250},42,[36,1252,56],{"emptyLinePlaceholder":55},[36,1254,1256],{"class":38,"line":1255},43,[36,1257,1258],{"class":42},"# ── Infinite loop with break ──\n",[36,1260,1262,1264,1267],{"class":38,"line":1261},44,[36,1263,780],{"class":62},[36,1265,1266],{"class":80}," ((;;)); ",[36,1268,817],{"class":62},[36,1270,1272,1275,1277],{"class":38,"line":1271},45,[36,1273,1274],{"class":80},"    ((count",[36,1276,1090],{"class":62},[36,1278,1279],{"class":80},"))\n",[36,1281,1283,1286,1289,1291,1294],{"class":38,"line":1282},46,[36,1284,1285],{"class":80},"    ((count ",[36,1287,1288],{"class":62},">=",[36,1290,1217],{"class":69},[36,1292,1293],{"class":80},")) && ",[36,1295,1296],{"class":62},"break\n",[36,1298,1300],{"class":38,"line":1299},47,[36,1301,833],{"class":62},[15,1303,1305,1308,1309],{"id":1304},"while-and-until",[19,1306,1307],{},"while"," and ",[19,1310,1311],{},"until",[24,1313,1314],{"language":26},[28,1315,1317],{"className":30,"code":1316,"language":26,"meta":32,"style":32},"# ── while: loop while condition is true (exit 0) ──\ncount=0\nwhile ((count \u003C 5)); do\n    echo \"count=$count\"\n    ((count++))\ndone\n\n# ── until: loop while condition is false (exit non-zero) ──\n# (until is just while with inverted condition)\nuntil ping -c 1 \"$host\" &>\u002Fdev\u002Fnull; do\n    echo \"waiting for $host...\"\n    sleep 1\ndone\necho \"$host is up\"\n\n# ── while with command condition (poll until success) ──\nwhile ! curl -s \"$health_url\" &>\u002Fdev\u002Fnull; do\n    echo \"waiting for health check...\"\n    sleep 2\ndone\necho \"healthy\"\n\n# ── while with command condition (read until EOF) ──\nwhile read -r line; do    # read returns non-zero at EOF → loop exits\n    echo \"$line\"\ndone \u003C file.txt\n",[19,1318,1319,1324,1334,1349,1361,1369,1373,1377,1382,1387,1411,1423,1431,1435,1446,1450,1455,1482,1489,1496,1500,1507,1511,1516,1536,1547],{"__ignoreMap":32},[36,1320,1321],{"class":38,"line":39},[36,1322,1323],{"class":42},"# ── while: loop while condition is true (exit 0) ──\n",[36,1325,1326,1329,1331],{"class":38,"line":46},[36,1327,1328],{"class":80},"count",[36,1330,948],{"class":62},[36,1332,1333],{"class":73},"0\n",[36,1335,1336,1338,1341,1343,1345,1347],{"class":38,"line":52},[36,1337,1307],{"class":62},[36,1339,1340],{"class":80}," ((count ",[36,1342,1081],{"class":62},[36,1344,1084],{"class":69},[36,1346,698],{"class":80},[36,1348,817],{"class":62},[36,1350,1351,1353,1356,1359],{"class":38,"line":59},[36,1352,93],{"class":69},[36,1354,1355],{"class":73}," \"count=",[36,1357,1358],{"class":80},"$count",[36,1360,382],{"class":73},[36,1362,1363,1365,1367],{"class":38,"line":90},[36,1364,1274],{"class":80},[36,1366,1090],{"class":62},[36,1368,1279],{"class":80},[36,1370,1371],{"class":38,"line":102},[36,1372,833],{"class":62},[36,1374,1375],{"class":38,"line":108},[36,1376,56],{"emptyLinePlaceholder":55},[36,1378,1379],{"class":38,"line":113},[36,1380,1381],{"class":42},"# ── until: loop while condition is false (exit non-zero) ──\n",[36,1383,1384],{"class":38,"line":143},[36,1385,1386],{"class":42},"# (until is just while with inverted condition)\n",[36,1388,1389,1391,1393,1395,1397,1399,1401,1403,1405,1407,1409],{"class":38,"line":158},[36,1390,1311],{"class":62},[36,1392,173],{"class":65},[36,1394,176],{"class":69},[36,1396,179],{"class":69},[36,1398,121],{"class":73},[36,1400,190],{"class":80},[36,1402,127],{"class":73},[36,1404,195],{"class":80},[36,1406,198],{"class":62},[36,1408,201],{"class":80},[36,1410,817],{"class":62},[36,1412,1413,1415,1418,1420],{"class":38,"line":163},[36,1414,93],{"class":69},[36,1416,1417],{"class":73}," \"waiting for ",[36,1419,190],{"class":80},[36,1421,1422],{"class":73},"...\"\n",[36,1424,1425,1428],{"class":38,"line":168},[36,1426,1427],{"class":65},"    sleep",[36,1429,1430],{"class":69}," 1\n",[36,1432,1433],{"class":38,"line":209},[36,1434,833],{"class":62},[36,1436,1437,1439,1441,1443],{"class":38,"line":217},[36,1438,482],{"class":69},[36,1440,121],{"class":73},[36,1442,190],{"class":80},[36,1444,1445],{"class":73}," is up\"\n",[36,1447,1448],{"class":38,"line":222},[36,1449,56],{"emptyLinePlaceholder":55},[36,1451,1452],{"class":38,"line":227},[36,1453,1454],{"class":42},"# ── while with command condition (poll until success) ──\n",[36,1456,1457,1459,1461,1464,1467,1469,1472,1474,1476,1478,1480],{"class":38,"line":252},[36,1458,1307],{"class":62},[36,1460,406],{"class":62},[36,1462,1463],{"class":65}," curl",[36,1465,1466],{"class":69}," -s",[36,1468,121],{"class":73},[36,1470,1471],{"class":80},"$health_url",[36,1473,127],{"class":73},[36,1475,195],{"class":80},[36,1477,198],{"class":62},[36,1479,201],{"class":80},[36,1481,817],{"class":62},[36,1483,1484,1486],{"class":38,"line":260},[36,1485,93],{"class":69},[36,1487,1488],{"class":73}," \"waiting for health check...\"\n",[36,1490,1491,1493],{"class":38,"line":265},[36,1492,1427],{"class":65},[36,1494,1495],{"class":69}," 2\n",[36,1497,1498],{"class":38,"line":270},[36,1499,833],{"class":62},[36,1501,1502,1504],{"class":38,"line":276},[36,1503,482],{"class":69},[36,1505,1506],{"class":73}," \"healthy\"\n",[36,1508,1509],{"class":38,"line":296},[36,1510,56],{"emptyLinePlaceholder":55},[36,1512,1513],{"class":38,"line":304},[36,1514,1515],{"class":42},"# ── while with command condition (read until EOF) ──\n",[36,1517,1518,1520,1523,1526,1529,1531,1533],{"class":38,"line":334},[36,1519,1307],{"class":62},[36,1521,1522],{"class":69}," read",[36,1524,1525],{"class":69}," -r",[36,1527,1528],{"class":73}," line",[36,1530,81],{"class":80},[36,1532,990],{"class":62},[36,1534,1535],{"class":42},"    # read returns non-zero at EOF → loop exits\n",[36,1537,1538,1540,1542,1545],{"class":38,"line":342},[36,1539,93],{"class":69},[36,1541,121],{"class":73},[36,1543,1544],{"class":80},"$line",[36,1546,382],{"class":73},[36,1548,1549,1552,1555],{"class":38,"line":357},[36,1550,1551],{"class":62},"done",[36,1553,1554],{"class":62}," \u003C",[36,1556,1557],{"class":80}," file.txt\n",[15,1559,1561,1564],{"id":1560},"while-ifs-read-r-the-canonical-line-reader",[19,1562,1563],{},"while IFS= read -r",": The Canonical Line Reader",[24,1566,1567],{"language":26},[28,1568,1570],{"className":30,"code":1569,"language":26,"meta":32,"style":32},"# ── Every part is load-bearing ──\n# IFS=    → don't trim leading\u002Ftrailing whitespace (default IFS=space\u002Ftab\u002Fnewline trims)\n# read    → read one line from stdin\n# -r      → don't interpret backslashes (without -r, \\t becomes tab, \\\\ becomes \\)\n# line    → variable to store the line\n\nwhile IFS= read -r line; do\n    printf '%s\\n' \"$line\"\ndone \u003C file.txt\n\n# ── Why IFS= matters ──\n# Input: \"  hello world  \"\n# With IFS= (empty): line=\"  hello world  \" (preserved)\n# Without IFS= (default): line=\"hello world\" (leading\u002Ftrailing whitespace trimmed)\n\n# ── Why -r matters ──\n# Input: \"path\\to\\file\"\n# With -r: line=\"path\\to\\file\" (literal backslashes)\n# Without -r: line=\"pathtofile\" (backslashes stripped, \\t → tab)\n\n# ── Reading multiple fields per line ──\nwhile IFS=, read -r name age city; do\n    # IFS=, sets the delimiter for THIS read only (not global)\n    echo \"$name ($age) from $city\"\ndone \u003C data.csv\n# CSV: \"Alice,30,NYC\" → name=Alice age=30 city=NYC\n# Last var gets the rest of the line (including any commas): \"Alice,30,NYC,USA\" → city=\"NYC,USA\"\n\n# ── Reading from a command (process substitution — avoids subshell trap) ──\nwhile IFS= read -r line; do\n    echo \"$line\"    # runs in MAIN shell — variables persist\ndone \u003C \u003C(grep \"error\" log.txt)\n\n# ── Reading with a different delimiter (null-delimited, for find -print0) ──\nwhile IFS= read -r -d '' file; do\n    # -d '' sets the delimiter to null byte (NUL)\n    # This is the ONLY safe way to handle filenames with spaces, newlines, or special chars\n    echo \"found: $file\"\ndone \u003C \u003C(find . -name '*.py' -print0)\n\n# ── Reading from a heredoc ──\nwhile IFS= read -r line; do\n    echo \"processing: $line\"\ndone \u003C\u003CEOF\nfirst line\nsecond line\nthird line\nEOF\n\n# ── Skipping blank lines and comments ──\nwhile IFS= read -r line; do\n    [[ -z \"$line\" ]] && continue          # skip blank lines\n    [[ \"$line\" =~ ^[[:space:]]*# ]] && continue  # skip comments\n    echo \"$line\"\ndone \u003C config.txt\n",[19,1571,1572,1577,1582,1587,1592,1597,1601,1620,1633,1641,1645,1650,1655,1660,1665,1669,1674,1679,1684,1689,1693,1698,1725,1730,1753,1762,1767,1772,1776,1781,1799,1812,1827,1831,1836,1861,1866,1871,1882,1907,1911,1916,1934,1945,1955,1960,1965,1970,1975,1980,1986,2005,2027,2055,2066],{"__ignoreMap":32},[36,1573,1574],{"class":38,"line":39},[36,1575,1576],{"class":42},"# ── Every part is load-bearing ──\n",[36,1578,1579],{"class":38,"line":46},[36,1580,1581],{"class":42},"# IFS=    → don't trim leading\u002Ftrailing whitespace (default IFS=space\u002Ftab\u002Fnewline trims)\n",[36,1583,1584],{"class":38,"line":52},[36,1585,1586],{"class":42},"# read    → read one line from stdin\n",[36,1588,1589],{"class":38,"line":59},[36,1590,1591],{"class":42},"# -r      → don't interpret backslashes (without -r, \\t becomes tab, \\\\ becomes \\)\n",[36,1593,1594],{"class":38,"line":90},[36,1595,1596],{"class":42},"# line    → variable to store the line\n",[36,1598,1599],{"class":38,"line":102},[36,1600,56],{"emptyLinePlaceholder":55},[36,1602,1603,1605,1608,1610,1612,1614,1616,1618],{"class":38,"line":108},[36,1604,1307],{"class":62},[36,1606,1607],{"class":80}," IFS",[36,1609,948],{"class":62},[36,1611,1522],{"class":69},[36,1613,1525],{"class":69},[36,1615,1528],{"class":73},[36,1617,81],{"class":80},[36,1619,817],{"class":62},[36,1621,1622,1624,1627,1629,1631],{"class":38,"line":113},[36,1623,1167],{"class":69},[36,1625,1626],{"class":73}," '%s\\n'",[36,1628,121],{"class":73},[36,1630,1544],{"class":80},[36,1632,382],{"class":73},[36,1634,1635,1637,1639],{"class":38,"line":143},[36,1636,1551],{"class":62},[36,1638,1554],{"class":62},[36,1640,1557],{"class":80},[36,1642,1643],{"class":38,"line":158},[36,1644,56],{"emptyLinePlaceholder":55},[36,1646,1647],{"class":38,"line":163},[36,1648,1649],{"class":42},"# ── Why IFS= matters ──\n",[36,1651,1652],{"class":38,"line":168},[36,1653,1654],{"class":42},"# Input: \"  hello world  \"\n",[36,1656,1657],{"class":38,"line":209},[36,1658,1659],{"class":42},"# With IFS= (empty): line=\"  hello world  \" (preserved)\n",[36,1661,1662],{"class":38,"line":217},[36,1663,1664],{"class":42},"# Without IFS= (default): line=\"hello world\" (leading\u002Ftrailing whitespace trimmed)\n",[36,1666,1667],{"class":38,"line":222},[36,1668,56],{"emptyLinePlaceholder":55},[36,1670,1671],{"class":38,"line":227},[36,1672,1673],{"class":42},"# ── Why -r matters ──\n",[36,1675,1676],{"class":38,"line":252},[36,1677,1678],{"class":42},"# Input: \"path\\to\\file\"\n",[36,1680,1681],{"class":38,"line":260},[36,1682,1683],{"class":42},"# With -r: line=\"path\\to\\file\" (literal backslashes)\n",[36,1685,1686],{"class":38,"line":265},[36,1687,1688],{"class":42},"# Without -r: line=\"pathtofile\" (backslashes stripped, \\t → tab)\n",[36,1690,1691],{"class":38,"line":270},[36,1692,56],{"emptyLinePlaceholder":55},[36,1694,1695],{"class":38,"line":276},[36,1696,1697],{"class":42},"# ── Reading multiple fields per line ──\n",[36,1699,1700,1702,1704,1706,1708,1710,1712,1715,1718,1721,1723],{"class":38,"line":296},[36,1701,1307],{"class":62},[36,1703,1607],{"class":80},[36,1705,948],{"class":62},[36,1707,1132],{"class":73},[36,1709,1522],{"class":69},[36,1711,1525],{"class":69},[36,1713,1714],{"class":73}," name",[36,1716,1717],{"class":73}," age",[36,1719,1720],{"class":73}," city",[36,1722,81],{"class":80},[36,1724,817],{"class":62},[36,1726,1727],{"class":38,"line":304},[36,1728,1729],{"class":42},"    # IFS=, sets the delimiter for THIS read only (not global)\n",[36,1731,1732,1734,1736,1739,1742,1745,1748,1751],{"class":38,"line":334},[36,1733,93],{"class":69},[36,1735,121],{"class":73},[36,1737,1738],{"class":80},"$name",[36,1740,1741],{"class":73}," (",[36,1743,1744],{"class":80},"$age",[36,1746,1747],{"class":73},") from ",[36,1749,1750],{"class":80},"$city",[36,1752,382],{"class":73},[36,1754,1755,1757,1759],{"class":38,"line":342},[36,1756,1551],{"class":62},[36,1758,1554],{"class":62},[36,1760,1761],{"class":80}," data.csv\n",[36,1763,1764],{"class":38,"line":357},[36,1765,1766],{"class":42},"# CSV: \"Alice,30,NYC\" → name=Alice age=30 city=NYC\n",[36,1768,1769],{"class":38,"line":365},[36,1770,1771],{"class":42},"# Last var gets the rest of the line (including any commas): \"Alice,30,NYC,USA\" → city=\"NYC,USA\"\n",[36,1773,1774],{"class":38,"line":371},[36,1775,56],{"emptyLinePlaceholder":55},[36,1777,1778],{"class":38,"line":385},[36,1779,1780],{"class":42},"# ── Reading from a command (process substitution — avoids subshell trap) ──\n",[36,1782,1783,1785,1787,1789,1791,1793,1795,1797],{"class":38,"line":390},[36,1784,1307],{"class":62},[36,1786,1607],{"class":80},[36,1788,948],{"class":62},[36,1790,1522],{"class":69},[36,1792,1525],{"class":69},[36,1794,1528],{"class":73},[36,1796,81],{"class":80},[36,1798,817],{"class":62},[36,1800,1801,1803,1805,1807,1809],{"class":38,"line":395},[36,1802,93],{"class":69},[36,1804,121],{"class":73},[36,1806,1544],{"class":80},[36,1808,127],{"class":73},[36,1810,1811],{"class":42},"    # runs in MAIN shell — variables persist\n",[36,1813,1814,1816,1818,1821,1824],{"class":38,"line":401},[36,1815,1551],{"class":62},[36,1817,1554],{"class":62},[36,1819,1820],{"class":73}," \u003C(",[36,1822,1823],{"class":65},"grep",[36,1825,1826],{"class":73}," \"error\" log.txt)\n",[36,1828,1829],{"class":38,"line":426},[36,1830,56],{"emptyLinePlaceholder":55},[36,1832,1833],{"class":38,"line":434},[36,1834,1835],{"class":42},"# ── Reading with a different delimiter (null-delimited, for find -print0) ──\n",[36,1837,1838,1840,1842,1844,1846,1848,1851,1854,1857,1859],{"class":38,"line":1164},[36,1839,1307],{"class":62},[36,1841,1607],{"class":80},[36,1843,948],{"class":62},[36,1845,1522],{"class":69},[36,1847,1525],{"class":69},[36,1849,1850],{"class":69}," -d",[36,1852,1853],{"class":73}," ''",[36,1855,1856],{"class":73}," file",[36,1858,81],{"class":80},[36,1860,817],{"class":62},[36,1862,1863],{"class":38,"line":1186},[36,1864,1865],{"class":42},"    # -d '' sets the delimiter to null byte (NUL)\n",[36,1867,1868],{"class":38,"line":1191},[36,1869,1870],{"class":42},"    # This is the ONLY safe way to handle filenames with spaces, newlines, or special chars\n",[36,1872,1873,1875,1878,1880],{"class":38,"line":1196},[36,1874,93],{"class":69},[36,1876,1877],{"class":73}," \"found: ",[36,1879,868],{"class":80},[36,1881,382],{"class":73},[36,1883,1884,1886,1888,1890,1893,1896,1899,1902,1905],{"class":38,"line":1202},[36,1885,1551],{"class":62},[36,1887,1554],{"class":62},[36,1889,1820],{"class":73},[36,1891,1892],{"class":65},"find",[36,1894,1895],{"class":73}," . ",[36,1897,1898],{"class":69},"-name",[36,1900,1901],{"class":73}," '*.py' ",[36,1903,1904],{"class":69},"-print0",[36,1906,963],{"class":73},[36,1908,1909],{"class":38,"line":1231},[36,1910,56],{"emptyLinePlaceholder":55},[36,1912,1913],{"class":38,"line":1245},[36,1914,1915],{"class":42},"# ── Reading from a heredoc ──\n",[36,1917,1918,1920,1922,1924,1926,1928,1930,1932],{"class":38,"line":1250},[36,1919,1307],{"class":62},[36,1921,1607],{"class":80},[36,1923,948],{"class":62},[36,1925,1522],{"class":69},[36,1927,1525],{"class":69},[36,1929,1528],{"class":73},[36,1931,81],{"class":80},[36,1933,817],{"class":62},[36,1935,1936,1938,1941,1943],{"class":38,"line":1255},[36,1937,93],{"class":69},[36,1939,1940],{"class":73}," \"processing: ",[36,1942,1544],{"class":80},[36,1944,382],{"class":73},[36,1946,1947,1949,1952],{"class":38,"line":1261},[36,1948,1551],{"class":62},[36,1950,1951],{"class":62}," \u003C\u003C",[36,1953,1954],{"class":73},"EOF\n",[36,1956,1957],{"class":38,"line":1271},[36,1958,1959],{"class":73},"first line\n",[36,1961,1962],{"class":38,"line":1282},[36,1963,1964],{"class":73},"second line\n",[36,1966,1967],{"class":38,"line":1299},[36,1968,1969],{"class":73},"third line\n",[36,1971,1973],{"class":38,"line":1972},48,[36,1974,1954],{"class":73},[36,1976,1978],{"class":38,"line":1977},49,[36,1979,56],{"emptyLinePlaceholder":55},[36,1981,1983],{"class":38,"line":1982},50,[36,1984,1985],{"class":42},"# ── Skipping blank lines and comments ──\n",[36,1987,1989,1991,1993,1995,1997,1999,2001,2003],{"class":38,"line":1988},51,[36,1990,1307],{"class":62},[36,1992,1607],{"class":80},[36,1994,948],{"class":62},[36,1996,1522],{"class":69},[36,1998,1525],{"class":69},[36,2000,1528],{"class":73},[36,2002,81],{"class":80},[36,2004,817],{"class":62},[36,2006,2008,2010,2013,2015,2017,2019,2021,2024],{"class":38,"line":2007},52,[36,2009,903],{"class":80},[36,2011,2012],{"class":62},"-z",[36,2014,121],{"class":73},[36,2016,1544],{"class":80},[36,2018,127],{"class":73},[36,2020,647],{"class":80},[36,2022,2023],{"class":62},"continue",[36,2025,2026],{"class":42},"          # skip blank lines\n",[36,2028,2030,2032,2034,2036,2038,2041,2044,2047,2050,2052],{"class":38,"line":2029},53,[36,2031,903],{"class":80},[36,2033,127],{"class":73},[36,2035,1544],{"class":80},[36,2037,127],{"class":73},[36,2039,2040],{"class":62}," =~",[36,2042,2043],{"class":80}," ^[[:space:]]",[36,2045,2046],{"class":62},"*",[36,2048,2049],{"class":80},"# ]] && ",[36,2051,2023],{"class":62},[36,2053,2054],{"class":42},"  # skip comments\n",[36,2056,2058,2060,2062,2064],{"class":38,"line":2057},54,[36,2059,93],{"class":69},[36,2061,121],{"class":73},[36,2063,1544],{"class":80},[36,2065,382],{"class":73},[36,2067,2069,2071,2073],{"class":38,"line":2068},55,[36,2070,1551],{"class":62},[36,2072,1554],{"class":62},[36,2074,2075],{"class":80}," config.txt\n",[15,2077,2079,2080],{"id":2078},"anti-pattern-for-line-in-cat-file","Anti-Pattern: ",[19,2081,2082],{},"for line in $(cat file)",[24,2084,2085],{"language":26},[28,2086,2088],{"className":30,"code":2087,"language":26,"meta":32,"style":32},"# ❌ NAIVE — for over cat output (word-splits on whitespace, breaks on spaces)\nfor line in $(cat file.txt); do\n    echo \"$line\"\ndone\n# \"hello world\" becomes two iterations: \"hello\" and \"world\"\n# Also forks a cat subprocess (unnecessary).\n\n# ✅ CORRECT — while read (line-by-line, no splitting)\nwhile IFS= read -r line; do\n    echo \"$line\"\ndone \u003C file.txt\n# No subprocess, no word splitting, backslashes preserved, whitespace preserved.\n\n# ── Why for $(cat) fails ──\n# $(cat file.txt) captures all output as ONE string.\n# for ... in \u003Cstring> splits the string on IFS (whitespace by default).\n# So \"hello world\\nfoo\" becomes three words: \"hello\" \"world\" \"foo\".\n# Even with IFS=$'\\n', it still forks cat unnecessarily.\n",[19,2089,2090,2095,2117,2127,2131,2136,2141,2145,2150,2168,2178,2186,2191,2195,2200,2205,2210,2215],{"__ignoreMap":32},[36,2091,2092],{"class":38,"line":39},[36,2093,2094],{"class":42},"# ❌ NAIVE — for over cat output (word-splits on whitespace, breaks on spaces)\n",[36,2096,2097,2099,2102,2104,2107,2110,2112,2115],{"class":38,"line":46},[36,2098,780],{"class":62},[36,2100,2101],{"class":80}," line ",[36,2103,803],{"class":62},[36,2105,2106],{"class":80}," $(",[36,2108,2109],{"class":65},"cat",[36,2111,416],{"class":73},[36,2113,2114],{"class":80},"); ",[36,2116,817],{"class":62},[36,2118,2119,2121,2123,2125],{"class":38,"line":52},[36,2120,93],{"class":69},[36,2122,121],{"class":73},[36,2124,1544],{"class":80},[36,2126,382],{"class":73},[36,2128,2129],{"class":38,"line":59},[36,2130,833],{"class":62},[36,2132,2133],{"class":38,"line":90},[36,2134,2135],{"class":42},"# \"hello world\" becomes two iterations: \"hello\" and \"world\"\n",[36,2137,2138],{"class":38,"line":102},[36,2139,2140],{"class":42},"# Also forks a cat subprocess (unnecessary).\n",[36,2142,2143],{"class":38,"line":108},[36,2144,56],{"emptyLinePlaceholder":55},[36,2146,2147],{"class":38,"line":113},[36,2148,2149],{"class":42},"# ✅ CORRECT — while read (line-by-line, no splitting)\n",[36,2151,2152,2154,2156,2158,2160,2162,2164,2166],{"class":38,"line":143},[36,2153,1307],{"class":62},[36,2155,1607],{"class":80},[36,2157,948],{"class":62},[36,2159,1522],{"class":69},[36,2161,1525],{"class":69},[36,2163,1528],{"class":73},[36,2165,81],{"class":80},[36,2167,817],{"class":62},[36,2169,2170,2172,2174,2176],{"class":38,"line":158},[36,2171,93],{"class":69},[36,2173,121],{"class":73},[36,2175,1544],{"class":80},[36,2177,382],{"class":73},[36,2179,2180,2182,2184],{"class":38,"line":163},[36,2181,1551],{"class":62},[36,2183,1554],{"class":62},[36,2185,1557],{"class":80},[36,2187,2188],{"class":38,"line":168},[36,2189,2190],{"class":42},"# No subprocess, no word splitting, backslashes preserved, whitespace preserved.\n",[36,2192,2193],{"class":38,"line":209},[36,2194,56],{"emptyLinePlaceholder":55},[36,2196,2197],{"class":38,"line":217},[36,2198,2199],{"class":42},"# ── Why for $(cat) fails ──\n",[36,2201,2202],{"class":38,"line":222},[36,2203,2204],{"class":42},"# $(cat file.txt) captures all output as ONE string.\n",[36,2206,2207],{"class":38,"line":227},[36,2208,2209],{"class":42},"# for ... in \u003Cstring> splits the string on IFS (whitespace by default).\n",[36,2211,2212],{"class":38,"line":252},[36,2213,2214],{"class":42},"# So \"hello world\\nfoo\" becomes three words: \"hello\" \"world\" \"foo\".\n",[36,2216,2217],{"class":38,"line":260},[36,2218,2219],{"class":42},"# Even with IFS=$'\\n', it still forks cat unnecessarily.\n",[15,2221,2223],{"id":2222},"the-pipe-into-while-subshell-trap","The Pipe-into-While Subshell Trap",[24,2225,2226],{"language":26},[28,2227,2229],{"className":30,"code":2228,"language":26,"meta":32,"style":32},"# ❌ NAIVE — variables set in while-after-pipe are lost (subshell!)\ntotal=0\necho -e \"1\\n2\\n3\" | while read -r num; do\n    total=$((total + num))    # set in SUBSHELL (the right side of | runs in a subshell)\ndone\necho \"total=$total\"          # total=0 — subshell's changes didn't propagate!\n\n# ✅ CORRECT — process substitution avoids the subshell\ntotal=0\nwhile read -r num; do\n    total=$((total + num))    # set in MAIN shell\ndone \u003C \u003C(echo -e \"1\\n2\\n3\")  # \u003C() feeds stdin WITHOUT creating a subshell for the while body\necho \"total=$total\"          # total=6 — correct!\n\n# ✅ ALTERNATIVE — here-string (for short input)\ntotal=0\nwhile read -r num; do\n    total=$((total + num))\ndone \u003C\u003C\u003C \"$(echo -e '1\\n2\\n3')\"\necho \"total=$total\"          # total=6 — correct\n\n# ── Why the pipe creates a subshell ──\n# In `cmd1 | cmd2`, cmd2 runs in a subshell (a fork of the main shell).\n# Any variable assignments in cmd2 (the while loop) are lost when the subshell exits.\n# Process substitution \u003C(...) provides cmd1's output as a file descriptor —\n# the while loop stays in the main shell and reads from that fd.\n",[19,2230,2231,2236,2245,2272,2295,2299,2314,2318,2323,2331,2345,2364,2382,2395,2399,2404,2412,2426,2442,2459,2472,2476,2481,2486,2491,2496],{"__ignoreMap":32},[36,2232,2233],{"class":38,"line":39},[36,2234,2235],{"class":42},"# ❌ NAIVE — variables set in while-after-pipe are lost (subshell!)\n",[36,2237,2238,2241,2243],{"class":38,"line":46},[36,2239,2240],{"class":80},"total",[36,2242,948],{"class":62},[36,2244,1333],{"class":73},[36,2246,2247,2249,2252,2255,2258,2261,2263,2265,2268,2270],{"class":38,"line":52},[36,2248,482],{"class":69},[36,2250,2251],{"class":69}," -e",[36,2253,2254],{"class":73}," \"1\\n2\\n3\"",[36,2256,2257],{"class":62}," |",[36,2259,2260],{"class":62}," while",[36,2262,1522],{"class":69},[36,2264,1525],{"class":69},[36,2266,2267],{"class":73}," num",[36,2269,81],{"class":80},[36,2271,817],{"class":62},[36,2273,2274,2277,2279,2282,2284,2287,2289,2292],{"class":38,"line":59},[36,2275,2276],{"class":80},"    total",[36,2278,948],{"class":62},[36,2280,2281],{"class":80},"$((",[36,2283,2240],{"class":65},[36,2285,2286],{"class":73}," +",[36,2288,2267],{"class":73},[36,2290,2291],{"class":80},"))    ",[36,2293,2294],{"class":42},"# set in SUBSHELL (the right side of | runs in a subshell)\n",[36,2296,2297],{"class":38,"line":90},[36,2298,833],{"class":62},[36,2300,2301,2303,2306,2309,2311],{"class":38,"line":102},[36,2302,482],{"class":69},[36,2304,2305],{"class":73}," \"total=",[36,2307,2308],{"class":80},"$total",[36,2310,127],{"class":73},[36,2312,2313],{"class":42},"          # total=0 — subshell's changes didn't propagate!\n",[36,2315,2316],{"class":38,"line":108},[36,2317,56],{"emptyLinePlaceholder":55},[36,2319,2320],{"class":38,"line":113},[36,2321,2322],{"class":42},"# ✅ CORRECT — process substitution avoids the subshell\n",[36,2324,2325,2327,2329],{"class":38,"line":143},[36,2326,2240],{"class":80},[36,2328,948],{"class":62},[36,2330,1333],{"class":73},[36,2332,2333,2335,2337,2339,2341,2343],{"class":38,"line":158},[36,2334,1307],{"class":62},[36,2336,1522],{"class":69},[36,2338,1525],{"class":69},[36,2340,2267],{"class":73},[36,2342,81],{"class":80},[36,2344,817],{"class":62},[36,2346,2347,2349,2351,2353,2355,2357,2359,2361],{"class":38,"line":163},[36,2348,2276],{"class":80},[36,2350,948],{"class":62},[36,2352,2281],{"class":80},[36,2354,2240],{"class":65},[36,2356,2286],{"class":73},[36,2358,2267],{"class":73},[36,2360,2291],{"class":80},[36,2362,2363],{"class":42},"# set in MAIN shell\n",[36,2365,2366,2368,2370,2372,2374,2376,2379],{"class":38,"line":168},[36,2367,1551],{"class":62},[36,2369,1554],{"class":62},[36,2371,1820],{"class":73},[36,2373,482],{"class":69},[36,2375,2251],{"class":69},[36,2377,2378],{"class":73}," \"1\\n2\\n3\")",[36,2380,2381],{"class":42},"  # \u003C() feeds stdin WITHOUT creating a subshell for the while body\n",[36,2383,2384,2386,2388,2390,2392],{"class":38,"line":209},[36,2385,482],{"class":69},[36,2387,2305],{"class":73},[36,2389,2308],{"class":80},[36,2391,127],{"class":73},[36,2393,2394],{"class":42},"          # total=6 — correct!\n",[36,2396,2397],{"class":38,"line":217},[36,2398,56],{"emptyLinePlaceholder":55},[36,2400,2401],{"class":38,"line":222},[36,2402,2403],{"class":42},"# ✅ ALTERNATIVE — here-string (for short input)\n",[36,2405,2406,2408,2410],{"class":38,"line":227},[36,2407,2240],{"class":80},[36,2409,948],{"class":62},[36,2411,1333],{"class":73},[36,2413,2414,2416,2418,2420,2422,2424],{"class":38,"line":252},[36,2415,1307],{"class":62},[36,2417,1522],{"class":69},[36,2419,1525],{"class":69},[36,2421,2267],{"class":73},[36,2423,81],{"class":80},[36,2425,817],{"class":62},[36,2427,2428,2430,2432,2434,2436,2438,2440],{"class":38,"line":260},[36,2429,2276],{"class":80},[36,2431,948],{"class":62},[36,2433,2281],{"class":80},[36,2435,2240],{"class":65},[36,2437,2286],{"class":73},[36,2439,2267],{"class":73},[36,2441,1279],{"class":80},[36,2443,2444,2446,2449,2452,2454,2456],{"class":38,"line":265},[36,2445,1551],{"class":62},[36,2447,2448],{"class":62}," \u003C\u003C\u003C",[36,2450,2451],{"class":73}," \"$(",[36,2453,482],{"class":69},[36,2455,2251],{"class":69},[36,2457,2458],{"class":73}," '1\\n2\\n3')\"\n",[36,2460,2461,2463,2465,2467,2469],{"class":38,"line":270},[36,2462,482],{"class":69},[36,2464,2305],{"class":73},[36,2466,2308],{"class":80},[36,2468,127],{"class":73},[36,2470,2471],{"class":42},"          # total=6 — correct\n",[36,2473,2474],{"class":38,"line":276},[36,2475,56],{"emptyLinePlaceholder":55},[36,2477,2478],{"class":38,"line":296},[36,2479,2480],{"class":42},"# ── Why the pipe creates a subshell ──\n",[36,2482,2483],{"class":38,"line":304},[36,2484,2485],{"class":42},"# In `cmd1 | cmd2`, cmd2 runs in a subshell (a fork of the main shell).\n",[36,2487,2488],{"class":38,"line":334},[36,2489,2490],{"class":42},"# Any variable assignments in cmd2 (the while loop) are lost when the subshell exits.\n",[36,2492,2493],{"class":38,"line":342},[36,2494,2495],{"class":42},"# Process substitution \u003C(...) provides cmd1's output as a file descriptor —\n",[36,2497,2498],{"class":38,"line":357},[36,2499,2500],{"class":42},"# the while loop stays in the main shell and reads from that fd.\n",[15,2502,2504,2507],{"id":2503},"case-glob-based-dispatch",[19,2505,2506],{},"case",": Glob-Based Dispatch",[24,2509,2510],{"language":26},[28,2511,2513],{"className":30,"code":2512,"language":26,"meta":32,"style":32},"# ── case matches the first matching glob pattern ──\ncase \"$1\" in\n    start)\n        echo \"starting...\"\n        ;;\n    stop)\n        echo \"stopping...\"\n        ;;\n    restart|reload)         # | = alternation (match either)\n        echo \"restarting...\"\n        ;;\n    --*)\n        echo \"long option: $1\"   # --* matches anything starting with --\n        ;;\n    *)\n        echo \"usage: $0 {start|stop|restart}\" >&2\n        exit 1\n        ;;\nesac\n\n# ── Patterns are GLOBS, not regex ──\ncase \"$file\" in\n    *.jpg|*.png|*.gif)   echo \"image: $file\" ;;   # glob: * matches any chars\n    [A-Z]*)            echo \"uppercase start\" ;;  # [A-Z] char class\n    *)                 echo \"other\" ;;\nesac\n\n# ── Capturing subpatterns: case doesn't support capture groups ──\n# Use [[ =~ ]] with BASH_REMATCH for capture groups:\nif [[ $1 =~ ^--([^=]+)=(.*)$ ]]; then\n    key=\"${BASH_REMATCH[1]}\"   # e.g. \"output\" from \"--output=file.txt\"\n    value=\"${BASH_REMATCH[2]}\" # e.g. \"file.txt\"\n    echo \"key=$key value=$value\"\nfi\n\n# ── Fall-through: ;;& (test next pattern) vs ;& (run next body) ──\n# Bash 4+ has ;;& and ;& for fall-through:\ncase \"$x\" in\n    *.txt)\n        echo \"text file\"\n        ;;&                    # ;;& — continue testing patterns below\n    *.gz)\n        echo \"gzipped\"\n        ;;\nesac\n# If x=\"file.txt.gz\": prints \"text file\" then \"gzipped\" (both matched with ;;&)\n\ncase \"$x\" in\n    *.txt)\n        echo \"text file\"\n        ;&                     # ;& — fall through to next body WITHOUT testing pattern\n    *.gz)\n        echo \"gzipped\"         # always runs if *.txt matched (no re-test)\n        ;;\nesac\n# If x=\"file.txt\": prints \"text file\" then \"gzipped\" (fell through without matching *.gz)\n\n# ── Subcommand dispatch pattern ──\ncase \"${1:-help}\" in\n    build)   shift; cmd_build \"$@\" ;;\n    test)    shift; cmd_test \"$@\" ;;\n    deploy)  shift; cmd_deploy \"$@\" ;;\n    help|-h|--help) usage ;;\n    *)       echo \"unknown: $1\" >&2; usage; exit 1 ;;\nesac\n",[19,2514,2515,2520,2534,2542,2550,2555,2562,2569,2573,2590,2597,2601,2610,2624,2628,2633,2649,2656,2660,2665,2669,2674,2686,2723,2744,2758,2762,2766,2771,2776,2814,2833,2850,2868,2872,2876,2881,2886,2899,2908,2915,2943,2952,2959,2963,2967,2972,2976,2988,2996,3002,3010,3017,3027,3031,3035,3041,3046,3052,3075,3099,3123,3147,3170,3199],{"__ignoreMap":32},[36,2516,2517],{"class":38,"line":39},[36,2518,2519],{"class":42},"# ── case matches the first matching glob pattern ──\n",[36,2521,2522,2524,2526,2529,2531],{"class":38,"line":46},[36,2523,2506],{"class":62},[36,2525,121],{"class":73},[36,2527,2528],{"class":69},"$1",[36,2530,127],{"class":73},[36,2532,2533],{"class":62}," in\n",[36,2535,2536,2540],{"class":38,"line":52},[36,2537,2539],{"class":2538},"svAP2","    start",[36,2541,963],{"class":62},[36,2543,2544,2547],{"class":38,"line":59},[36,2545,2546],{"class":69},"        echo",[36,2548,2549],{"class":73}," \"starting...\"\n",[36,2551,2552],{"class":38,"line":90},[36,2553,2554],{"class":80},"        ;;\n",[36,2556,2557,2560],{"class":38,"line":102},[36,2558,2559],{"class":2538},"    stop",[36,2561,963],{"class":62},[36,2563,2564,2566],{"class":38,"line":108},[36,2565,2546],{"class":69},[36,2567,2568],{"class":73}," \"stopping...\"\n",[36,2570,2571],{"class":38,"line":113},[36,2572,2554],{"class":80},[36,2574,2575,2578,2581,2584,2587],{"class":38,"line":143},[36,2576,2577],{"class":2538},"    restart",[36,2579,2580],{"class":62},"|",[36,2582,2583],{"class":2538},"reload",[36,2585,2586],{"class":62},")",[36,2588,2589],{"class":42},"         # | = alternation (match either)\n",[36,2591,2592,2594],{"class":38,"line":158},[36,2593,2546],{"class":69},[36,2595,2596],{"class":73}," \"restarting...\"\n",[36,2598,2599],{"class":38,"line":163},[36,2600,2554],{"class":80},[36,2602,2603,2606,2608],{"class":38,"line":168},[36,2604,2605],{"class":2538},"    --",[36,2607,2046],{"class":62},[36,2609,963],{"class":62},[36,2611,2612,2614,2617,2619,2621],{"class":38,"line":209},[36,2613,2546],{"class":69},[36,2615,2616],{"class":73}," \"long option: ",[36,2618,2528],{"class":69},[36,2620,127],{"class":73},[36,2622,2623],{"class":42},"   # --* matches anything starting with --\n",[36,2625,2626],{"class":38,"line":217},[36,2627,2554],{"class":80},[36,2629,2630],{"class":38,"line":222},[36,2631,2632],{"class":62},"    *)\n",[36,2634,2635,2637,2640,2643,2646],{"class":38,"line":227},[36,2636,2546],{"class":69},[36,2638,2639],{"class":73}," \"usage: ",[36,2641,2642],{"class":69},"$0",[36,2644,2645],{"class":73}," {start|stop|restart}\"",[36,2647,2648],{"class":62}," >&2\n",[36,2650,2651,2654],{"class":38,"line":252},[36,2652,2653],{"class":69},"        exit",[36,2655,1430],{"class":69},[36,2657,2658],{"class":38,"line":260},[36,2659,2554],{"class":80},[36,2661,2662],{"class":38,"line":265},[36,2663,2664],{"class":62},"esac\n",[36,2666,2667],{"class":38,"line":270},[36,2668,56],{"emptyLinePlaceholder":55},[36,2670,2671],{"class":38,"line":276},[36,2672,2673],{"class":42},"# ── Patterns are GLOBS, not regex ──\n",[36,2675,2676,2678,2680,2682,2684],{"class":38,"line":296},[36,2677,2506],{"class":62},[36,2679,121],{"class":73},[36,2681,868],{"class":80},[36,2683,127],{"class":73},[36,2685,2533],{"class":62},[36,2687,2688,2691,2694,2697,2700,2702,2705,2707,2710,2713,2715,2717,2720],{"class":38,"line":304},[36,2689,2690],{"class":62},"    *",[36,2692,2693],{"class":2538},".jpg",[36,2695,2696],{"class":62},"|*",[36,2698,2699],{"class":2538},".png",[36,2701,2696],{"class":62},[36,2703,2704],{"class":2538},".gif",[36,2706,2586],{"class":62},[36,2708,2709],{"class":69},"   echo",[36,2711,2712],{"class":73}," \"image: ",[36,2714,868],{"class":80},[36,2716,127],{"class":73},[36,2718,2719],{"class":80}," ;;   ",[36,2721,2722],{"class":42},"# glob: * matches any chars\n",[36,2724,2725,2728,2730,2732,2735,2738,2741],{"class":38,"line":334},[36,2726,2727],{"class":2538},"    [A-Z]",[36,2729,2046],{"class":62},[36,2731,2586],{"class":62},[36,2733,2734],{"class":69},"            echo",[36,2736,2737],{"class":73}," \"uppercase start\"",[36,2739,2740],{"class":80}," ;;  ",[36,2742,2743],{"class":42},"# [A-Z] char class\n",[36,2745,2746,2749,2752,2755],{"class":38,"line":342},[36,2747,2748],{"class":62},"    *)",[36,2750,2751],{"class":69},"                 echo",[36,2753,2754],{"class":73}," \"other\"",[36,2756,2757],{"class":80}," ;;\n",[36,2759,2760],{"class":38,"line":357},[36,2761,2664],{"class":62},[36,2763,2764],{"class":38,"line":365},[36,2765,56],{"emptyLinePlaceholder":55},[36,2767,2768],{"class":38,"line":371},[36,2769,2770],{"class":42},"# ── Capturing subpatterns: case doesn't support capture groups ──\n",[36,2772,2773],{"class":38,"line":385},[36,2774,2775],{"class":42},"# Use [[ =~ ]] with BASH_REMATCH for capture groups:\n",[36,2777,2778,2780,2783,2786,2788,2791,2794,2797,2800,2802,2804,2807,2809,2812],{"class":38,"line":390},[36,2779,21],{"class":62},[36,2781,2782],{"class":80}," [[ ",[36,2784,2528],{"class":2785},"sCrzJ",[36,2787,2040],{"class":62},[36,2789,2790],{"class":80}," ^--([",[36,2792,2793],{"class":62},"^=",[36,2795,2796],{"class":80},"]",[36,2798,2799],{"class":62},"+",[36,2801,2586],{"class":80},[36,2803,948],{"class":62},[36,2805,2806],{"class":80},"(.",[36,2808,2046],{"class":62},[36,2810,2811],{"class":80},")$ ]]; ",[36,2813,293],{"class":62},[36,2815,2816,2819,2821,2824,2827,2830],{"class":38,"line":395},[36,2817,2818],{"class":80},"    key",[36,2820,948],{"class":62},[36,2822,2823],{"class":73},"\"${",[36,2825,2826],{"class":80},"BASH_REMATCH",[36,2828,2829],{"class":73},"[1]}\"",[36,2831,2832],{"class":42},"   # e.g. \"output\" from \"--output=file.txt\"\n",[36,2834,2835,2838,2840,2842,2844,2847],{"class":38,"line":401},[36,2836,2837],{"class":80},"    value",[36,2839,948],{"class":62},[36,2841,2823],{"class":73},[36,2843,2826],{"class":80},[36,2845,2846],{"class":73},"[2]}\"",[36,2848,2849],{"class":42}," # e.g. \"file.txt\"\n",[36,2851,2852,2854,2857,2860,2863,2866],{"class":38,"line":426},[36,2853,93],{"class":69},[36,2855,2856],{"class":73}," \"key=",[36,2858,2859],{"class":80},"$key",[36,2861,2862],{"class":73}," value=",[36,2864,2865],{"class":80},"$value",[36,2867,382],{"class":73},[36,2869,2870],{"class":38,"line":434},[36,2871,105],{"class":62},[36,2873,2874],{"class":38,"line":1164},[36,2875,56],{"emptyLinePlaceholder":55},[36,2877,2878],{"class":38,"line":1186},[36,2879,2880],{"class":42},"# ── Fall-through: ;;& (test next pattern) vs ;& (run next body) ──\n",[36,2882,2883],{"class":38,"line":1191},[36,2884,2885],{"class":42},"# Bash 4+ has ;;& and ;& for fall-through:\n",[36,2887,2888,2890,2892,2895,2897],{"class":38,"line":1196},[36,2889,2506],{"class":62},[36,2891,121],{"class":73},[36,2893,2894],{"class":80},"$x",[36,2896,127],{"class":73},[36,2898,2533],{"class":62},[36,2900,2901,2903,2906],{"class":38,"line":1202},[36,2902,2690],{"class":62},[36,2904,2905],{"class":2538},".txt",[36,2907,963],{"class":62},[36,2909,2910,2912],{"class":38,"line":1231},[36,2911,2546],{"class":69},[36,2913,2914],{"class":73}," \"text file\"\n",[36,2916,2917,2920,2923,2926,2929,2932,2934,2937,2940],{"class":38,"line":1245},[36,2918,2919],{"class":80},"        ;;",[36,2921,2922],{"class":2538},"&",[36,2924,2925],{"class":2538},"                    #",[36,2927,2928],{"class":2538}," ;;&",[36,2930,2931],{"class":2538}," —",[36,2933,914],{"class":2538},[36,2935,2936],{"class":2538}," testing",[36,2938,2939],{"class":2538}," patterns",[36,2941,2942],{"class":2538}," below\n",[36,2944,2945,2947,2950],{"class":38,"line":1250},[36,2946,2690],{"class":62},[36,2948,2949],{"class":2538},".gz",[36,2951,963],{"class":62},[36,2953,2954,2956],{"class":38,"line":1255},[36,2955,2546],{"class":69},[36,2957,2958],{"class":73}," \"gzipped\"\n",[36,2960,2961],{"class":38,"line":1261},[36,2962,2554],{"class":80},[36,2964,2965],{"class":38,"line":1271},[36,2966,2664],{"class":62},[36,2968,2969],{"class":38,"line":1282},[36,2970,2971],{"class":42},"# If x=\"file.txt.gz\": prints \"text file\" then \"gzipped\" (both matched with ;;&)\n",[36,2973,2974],{"class":38,"line":1299},[36,2975,56],{"emptyLinePlaceholder":55},[36,2977,2978,2980,2982,2984,2986],{"class":38,"line":1972},[36,2979,2506],{"class":62},[36,2981,121],{"class":73},[36,2983,2894],{"class":80},[36,2985,127],{"class":73},[36,2987,2533],{"class":62},[36,2989,2990,2992,2994],{"class":38,"line":1977},[36,2991,2690],{"class":62},[36,2993,2905],{"class":2538},[36,2995,963],{"class":62},[36,2997,2998,3000],{"class":38,"line":1982},[36,2999,2546],{"class":69},[36,3001,2914],{"class":73},[36,3003,3004,3007],{"class":38,"line":1988},[36,3005,3006],{"class":80},"        ;&                     ",[36,3008,3009],{"class":42},"# ;& — fall through to next body WITHOUT testing pattern\n",[36,3011,3012,3015],{"class":38,"line":2007},[36,3013,3014],{"class":65},"    *.gz",[36,3016,963],{"class":80},[36,3018,3019,3021,3024],{"class":38,"line":2029},[36,3020,2546],{"class":69},[36,3022,3023],{"class":73}," \"gzipped\"",[36,3025,3026],{"class":42},"         # always runs if *.txt matched (no re-test)\n",[36,3028,3029],{"class":38,"line":2057},[36,3030,2554],{"class":80},[36,3032,3033],{"class":38,"line":2068},[36,3034,2664],{"class":62},[36,3036,3038],{"class":38,"line":3037},56,[36,3039,3040],{"class":42},"# If x=\"file.txt\": prints \"text file\" then \"gzipped\" (fell through without matching *.gz)\n",[36,3042,3044],{"class":38,"line":3043},57,[36,3045,56],{"emptyLinePlaceholder":55},[36,3047,3049],{"class":38,"line":3048},58,[36,3050,3051],{"class":42},"# ── Subcommand dispatch pattern ──\n",[36,3053,3055,3057,3059,3062,3065,3068,3071,3073],{"class":38,"line":3054},59,[36,3056,2506],{"class":62},[36,3058,121],{"class":73},[36,3060,3061],{"class":69},"${1",[36,3063,3064],{"class":62},":-",[36,3066,3067],{"class":80},"help",[36,3069,3070],{"class":69},"}",[36,3072,127],{"class":73},[36,3074,2533],{"class":62},[36,3076,3078,3081,3083,3086,3088,3091,3093,3095,3097],{"class":38,"line":3077},60,[36,3079,3080],{"class":2538},"    build",[36,3082,2586],{"class":62},[36,3084,3085],{"class":69},"   shift",[36,3087,81],{"class":80},[36,3089,3090],{"class":65},"cmd_build",[36,3092,121],{"class":73},[36,3094,1030],{"class":69},[36,3096,127],{"class":73},[36,3098,2757],{"class":80},[36,3100,3102,3105,3107,3110,3112,3115,3117,3119,3121],{"class":38,"line":3101},61,[36,3103,3104],{"class":2538},"    test",[36,3106,2586],{"class":62},[36,3108,3109],{"class":69},"    shift",[36,3111,81],{"class":80},[36,3113,3114],{"class":65},"cmd_test",[36,3116,121],{"class":73},[36,3118,1030],{"class":69},[36,3120,127],{"class":73},[36,3122,2757],{"class":80},[36,3124,3126,3129,3131,3134,3136,3139,3141,3143,3145],{"class":38,"line":3125},62,[36,3127,3128],{"class":2538},"    deploy",[36,3130,2586],{"class":62},[36,3132,3133],{"class":69},"  shift",[36,3135,81],{"class":80},[36,3137,3138],{"class":65},"cmd_deploy",[36,3140,121],{"class":73},[36,3142,1030],{"class":69},[36,3144,127],{"class":73},[36,3146,2757],{"class":80},[36,3148,3150,3153,3155,3158,3160,3163,3165,3168],{"class":38,"line":3149},63,[36,3151,3152],{"class":2538},"    help",[36,3154,2580],{"class":62},[36,3156,3157],{"class":2538},"-h",[36,3159,2580],{"class":62},[36,3161,3162],{"class":2538},"--help",[36,3164,2586],{"class":62},[36,3166,3167],{"class":65}," usage",[36,3169,2757],{"class":80},[36,3171,3173,3175,3178,3180,3182,3184,3186,3188,3191,3193,3195,3197],{"class":38,"line":3172},64,[36,3174,2748],{"class":62},[36,3176,3177],{"class":69},"       echo",[36,3179,376],{"class":73},[36,3181,2528],{"class":69},[36,3183,127],{"class":73},[36,3185,507],{"class":62},[36,3187,81],{"class":80},[36,3189,3190],{"class":65},"usage",[36,3192,81],{"class":80},[36,3194,512],{"class":69},[36,3196,179],{"class":69},[36,3198,2757],{"class":80},[36,3200,3202],{"class":38,"line":3201},65,[36,3203,2664],{"class":62},[15,3205,3207,1308,3210],{"id":3206},"break-and-continue",[19,3208,3209],{},"break",[19,3211,2023],{},[24,3213,3214],{"language":26},[28,3215,3217],{"className":30,"code":3216,"language":26,"meta":32,"style":32},"# ── break: exit the loop ──\nfor i in {1..10}; do\n    ((i == 5)) && break   # stop at 5\n    echo \"$i\"\ndone\n# prints: 1 2 3 4\n\n# ── continue: skip to next iteration ──\nfor i in {1..10}; do\n    ((i % 2 == 0)) && continue   # skip even numbers\n    echo \"$i\"\ndone\n# prints: 1 3 5 7 9\n\n# ── break N: break out of N nested loops ──\nfor i in {1..3}; do\n    for j in {1..3}; do\n        ((j == 2)) && break 2   # break out of BOTH loops\n        echo \"$i $j\"\n    done\ndone\n# prints: 1 1 (breaks on j=2, exits both loops)\n\n# ── continue N: continue the Nth outer loop ──\nfor i in {1..3}; do\n    for j in {1..3}; do\n        ((j == 2)) && continue 2   # skip to next i iteration\n        echo \"$i $j\"\n    done\ndone\n# prints: 1 1, 2 1, 3 1 (on j=2, skips to next i)\n",[19,3218,3219,3224,3243,3260,3270,3274,3279,3283,3288,3304,3325,3335,3339,3344,3348,3353,3370,3387,3405,3418,3423,3427,3432,3436,3441,3457,3473,3490,3502,3506,3510],{"__ignoreMap":32},[36,3220,3221],{"class":38,"line":39},[36,3222,3223],{"class":42},"# ── break: exit the loop ──\n",[36,3225,3226,3228,3231,3233,3236,3239,3241],{"class":38,"line":46},[36,3227,780],{"class":62},[36,3229,3230],{"class":80}," i ",[36,3232,803],{"class":62},[36,3234,3235],{"class":80}," {",[36,3237,3238],{"class":65},"1..10}",[36,3240,81],{"class":80},[36,3242,817],{"class":62},[36,3244,3245,3248,3251,3253,3255,3257],{"class":38,"line":52},[36,3246,3247],{"class":80},"    ((i ",[36,3249,3250],{"class":62},"==",[36,3252,1084],{"class":69},[36,3254,1293],{"class":80},[36,3256,3209],{"class":62},[36,3258,3259],{"class":42},"   # stop at 5\n",[36,3261,3262,3264,3266,3268],{"class":38,"line":59},[36,3263,93],{"class":69},[36,3265,121],{"class":73},[36,3267,1104],{"class":80},[36,3269,382],{"class":73},[36,3271,3272],{"class":38,"line":90},[36,3273,833],{"class":62},[36,3275,3276],{"class":38,"line":102},[36,3277,3278],{"class":42},"# prints: 1 2 3 4\n",[36,3280,3281],{"class":38,"line":108},[36,3282,56],{"emptyLinePlaceholder":55},[36,3284,3285],{"class":38,"line":113},[36,3286,3287],{"class":42},"# ── continue: skip to next iteration ──\n",[36,3289,3290,3292,3294,3296,3298,3300,3302],{"class":38,"line":143},[36,3291,780],{"class":62},[36,3293,3230],{"class":80},[36,3295,803],{"class":62},[36,3297,3235],{"class":80},[36,3299,3238],{"class":65},[36,3301,81],{"class":80},[36,3303,817],{"class":62},[36,3305,3306,3308,3311,3313,3316,3318,3320,3322],{"class":38,"line":158},[36,3307,3247],{"class":80},[36,3309,3310],{"class":62},"%",[36,3312,185],{"class":69},[36,3314,3315],{"class":62}," ==",[36,3317,637],{"class":69},[36,3319,1293],{"class":80},[36,3321,2023],{"class":62},[36,3323,3324],{"class":42},"   # skip even numbers\n",[36,3326,3327,3329,3331,3333],{"class":38,"line":163},[36,3328,93],{"class":69},[36,3330,121],{"class":73},[36,3332,1104],{"class":80},[36,3334,382],{"class":73},[36,3336,3337],{"class":38,"line":168},[36,3338,833],{"class":62},[36,3340,3341],{"class":38,"line":209},[36,3342,3343],{"class":42},"# prints: 1 3 5 7 9\n",[36,3345,3346],{"class":38,"line":217},[36,3347,56],{"emptyLinePlaceholder":55},[36,3349,3350],{"class":38,"line":222},[36,3351,3352],{"class":42},"# ── break N: break out of N nested loops ──\n",[36,3354,3355,3357,3359,3361,3363,3366,3368],{"class":38,"line":227},[36,3356,780],{"class":62},[36,3358,3230],{"class":80},[36,3360,803],{"class":62},[36,3362,3235],{"class":80},[36,3364,3365],{"class":65},"1..3}",[36,3367,81],{"class":80},[36,3369,817],{"class":62},[36,3371,3372,3375,3377,3379,3381,3383,3385],{"class":38,"line":252},[36,3373,3374],{"class":62},"    for",[36,3376,1135],{"class":80},[36,3378,803],{"class":62},[36,3380,3235],{"class":80},[36,3382,3365],{"class":65},[36,3384,81],{"class":80},[36,3386,817],{"class":62},[36,3388,3389,3392,3394,3396,3398,3400,3402],{"class":38,"line":260},[36,3390,3391],{"class":80},"        ((j ",[36,3393,3250],{"class":62},[36,3395,185],{"class":69},[36,3397,1293],{"class":80},[36,3399,3209],{"class":62},[36,3401,185],{"class":69},[36,3403,3404],{"class":42},"   # break out of BOTH loops\n",[36,3406,3407,3409,3411,3413,3416],{"class":38,"line":265},[36,3408,2546],{"class":69},[36,3410,121],{"class":73},[36,3412,1104],{"class":80},[36,3414,3415],{"class":80}," $j",[36,3417,382],{"class":73},[36,3419,3420],{"class":38,"line":270},[36,3421,3422],{"class":62},"    done\n",[36,3424,3425],{"class":38,"line":276},[36,3426,833],{"class":62},[36,3428,3429],{"class":38,"line":296},[36,3430,3431],{"class":42},"# prints: 1 1 (breaks on j=2, exits both loops)\n",[36,3433,3434],{"class":38,"line":304},[36,3435,56],{"emptyLinePlaceholder":55},[36,3437,3438],{"class":38,"line":334},[36,3439,3440],{"class":42},"# ── continue N: continue the Nth outer loop ──\n",[36,3442,3443,3445,3447,3449,3451,3453,3455],{"class":38,"line":342},[36,3444,780],{"class":62},[36,3446,3230],{"class":80},[36,3448,803],{"class":62},[36,3450,3235],{"class":80},[36,3452,3365],{"class":65},[36,3454,81],{"class":80},[36,3456,817],{"class":62},[36,3458,3459,3461,3463,3465,3467,3469,3471],{"class":38,"line":357},[36,3460,3374],{"class":62},[36,3462,1135],{"class":80},[36,3464,803],{"class":62},[36,3466,3235],{"class":80},[36,3468,3365],{"class":65},[36,3470,81],{"class":80},[36,3472,817],{"class":62},[36,3474,3475,3477,3479,3481,3483,3485,3487],{"class":38,"line":365},[36,3476,3391],{"class":80},[36,3478,3250],{"class":62},[36,3480,185],{"class":69},[36,3482,1293],{"class":80},[36,3484,2023],{"class":62},[36,3486,185],{"class":69},[36,3488,3489],{"class":42},"   # skip to next i iteration\n",[36,3491,3492,3494,3496,3498,3500],{"class":38,"line":371},[36,3493,2546],{"class":69},[36,3495,121],{"class":73},[36,3497,1104],{"class":80},[36,3499,3415],{"class":80},[36,3501,382],{"class":73},[36,3503,3504],{"class":38,"line":385},[36,3505,3422],{"class":62},[36,3507,3508],{"class":38,"line":390},[36,3509,833],{"class":62},[36,3511,3512],{"class":38,"line":395},[36,3513,3514],{"class":42},"# prints: 1 1, 2 1, 3 1 (on j=2, skips to next i)\n",[15,3516,3518,3521],{"id":3517},"select-interactive-menus",[19,3519,3520],{},"select",": Interactive Menus",[24,3523,3524],{"language":26},[28,3525,3527],{"className":30,"code":3526,"language":26,"meta":32,"style":32},"# ── select generates a numbered menu, reads choice into the variable ──\nPS3=\"Choose a fruit: \"        # PS3 is the prompt for select (like PS1 for shell prompt)\nselect fruit in apple banana cherry \"quit\"; do\n    case \"$fruit\" in\n        apple|banana|cherry)\n            echo \"you chose $fruit\"\n            ;;\n        quit)\n            break              # select loops until break\n            ;;\n        *)\n            echo \"invalid: $REPLY\"  # $REPLY is the raw input (the number or text)\n            ;;\n    esac\ndone\n\n# ── select with an array ──\noptions=(\"Build\" \"Test\" \"Deploy\" \"Quit\")\nPS3=\"> \"\nselect opt in \"${options[@]}\"; do\n    case \"$opt\" in\n        Build|Test|Deploy) echo \"running $opt...\" ;;\n        Quit) break ;;\n        *) echo \"invalid choice\" ;;\n    esac\ndone\n\n# ── select reads from stdin — redirect for non-interactive use ──\nselect opt in build test deploy; do\n    echo \"$opt\"\n    break\ndone \u003C\u003C\u003C \"build\"   # feeds \"build\" as input → opt=build\n",[19,3528,3529,3534,3547,3561,3574,3591,3602,3607,3614,3622,3626,3631,3646,3650,3655,3659,3663,3668,3691,3700,3721,3734,3763,3775,3787,3791,3795,3799,3804,3813,3823,3828],{"__ignoreMap":32},[36,3530,3531],{"class":38,"line":39},[36,3532,3533],{"class":42},"# ── select generates a numbered menu, reads choice into the variable ──\n",[36,3535,3536,3539,3541,3544],{"class":38,"line":46},[36,3537,3538],{"class":80},"PS3",[36,3540,948],{"class":62},[36,3542,3543],{"class":73},"\"Choose a fruit: \"",[36,3545,3546],{"class":42},"        # PS3 is the prompt for select (like PS1 for shell prompt)\n",[36,3548,3549,3551,3554,3557,3559],{"class":38,"line":52},[36,3550,3520],{"class":62},[36,3552,3553],{"class":80}," fruit in apple banana cherry ",[36,3555,3556],{"class":73},"\"quit\"",[36,3558,81],{"class":80},[36,3560,817],{"class":62},[36,3562,3563,3566,3568,3570,3572],{"class":38,"line":59},[36,3564,3565],{"class":62},"    case",[36,3567,121],{"class":73},[36,3569,826],{"class":80},[36,3571,127],{"class":73},[36,3573,2533],{"class":62},[36,3575,3576,3579,3581,3584,3586,3589],{"class":38,"line":90},[36,3577,3578],{"class":2538},"        apple",[36,3580,2580],{"class":62},[36,3582,3583],{"class":2538},"banana",[36,3585,2580],{"class":62},[36,3587,3588],{"class":2538},"cherry",[36,3590,963],{"class":62},[36,3592,3593,3595,3598,3600],{"class":38,"line":102},[36,3594,2734],{"class":69},[36,3596,3597],{"class":73}," \"you chose ",[36,3599,826],{"class":80},[36,3601,382],{"class":73},[36,3603,3604],{"class":38,"line":108},[36,3605,3606],{"class":80},"            ;;\n",[36,3608,3609,3612],{"class":38,"line":113},[36,3610,3611],{"class":2538},"        quit",[36,3613,963],{"class":62},[36,3615,3616,3619],{"class":38,"line":143},[36,3617,3618],{"class":62},"            break",[36,3620,3621],{"class":42},"              # select loops until break\n",[36,3623,3624],{"class":38,"line":158},[36,3625,3606],{"class":80},[36,3627,3628],{"class":38,"line":163},[36,3629,3630],{"class":62},"        *)\n",[36,3632,3633,3635,3638,3641,3643],{"class":38,"line":168},[36,3634,2734],{"class":69},[36,3636,3637],{"class":73}," \"invalid: ",[36,3639,3640],{"class":80},"$REPLY",[36,3642,127],{"class":73},[36,3644,3645],{"class":42},"  # $REPLY is the raw input (the number or text)\n",[36,3647,3648],{"class":38,"line":209},[36,3649,3606],{"class":80},[36,3651,3652],{"class":38,"line":217},[36,3653,3654],{"class":62},"    esac\n",[36,3656,3657],{"class":38,"line":222},[36,3658,833],{"class":62},[36,3660,3661],{"class":38,"line":227},[36,3662,56],{"emptyLinePlaceholder":55},[36,3664,3665],{"class":38,"line":252},[36,3666,3667],{"class":42},"# ── select with an array ──\n",[36,3669,3670,3673,3675,3677,3680,3683,3686,3689],{"class":38,"line":260},[36,3671,3672],{"class":80},"options",[36,3674,948],{"class":62},[36,3676,951],{"class":80},[36,3678,3679],{"class":73},"\"Build\"",[36,3681,3682],{"class":73}," \"Test\"",[36,3684,3685],{"class":73}," \"Deploy\"",[36,3687,3688],{"class":73}," \"Quit\"",[36,3690,963],{"class":80},[36,3692,3693,3695,3697],{"class":38,"line":265},[36,3694,3538],{"class":80},[36,3696,948],{"class":62},[36,3698,3699],{"class":73},"\"> \"\n",[36,3701,3702,3704,3707,3709,3711,3713,3715,3717,3719],{"class":38,"line":270},[36,3703,3520],{"class":62},[36,3705,3706],{"class":80}," opt in ",[36,3708,2823],{"class":73},[36,3710,3672],{"class":80},[36,3712,979],{"class":73},[36,3714,982],{"class":62},[36,3716,985],{"class":73},[36,3718,81],{"class":80},[36,3720,817],{"class":62},[36,3722,3723,3725,3727,3730,3732],{"class":38,"line":276},[36,3724,3565],{"class":62},[36,3726,121],{"class":73},[36,3728,3729],{"class":80},"$opt",[36,3731,127],{"class":73},[36,3733,2533],{"class":62},[36,3735,3736,3739,3741,3744,3746,3749,3751,3753,3756,3758,3761],{"class":38,"line":296},[36,3737,3738],{"class":2538},"        Build",[36,3740,2580],{"class":62},[36,3742,3743],{"class":2538},"Test",[36,3745,2580],{"class":62},[36,3747,3748],{"class":2538},"Deploy",[36,3750,2586],{"class":62},[36,3752,658],{"class":69},[36,3754,3755],{"class":73}," \"running ",[36,3757,3729],{"class":80},[36,3759,3760],{"class":73},"...\"",[36,3762,2757],{"class":80},[36,3764,3765,3768,3770,3773],{"class":38,"line":304},[36,3766,3767],{"class":2538},"        Quit",[36,3769,2586],{"class":62},[36,3771,3772],{"class":62}," break",[36,3774,2757],{"class":80},[36,3776,3777,3780,3782,3785],{"class":38,"line":334},[36,3778,3779],{"class":62},"        *)",[36,3781,658],{"class":69},[36,3783,3784],{"class":73}," \"invalid choice\"",[36,3786,2757],{"class":80},[36,3788,3789],{"class":38,"line":342},[36,3790,3654],{"class":62},[36,3792,3793],{"class":38,"line":357},[36,3794,833],{"class":62},[36,3796,3797],{"class":38,"line":365},[36,3798,56],{"emptyLinePlaceholder":55},[36,3800,3801],{"class":38,"line":371},[36,3802,3803],{"class":42},"# ── select reads from stdin — redirect for non-interactive use ──\n",[36,3805,3806,3808,3811],{"class":38,"line":385},[36,3807,3520],{"class":62},[36,3809,3810],{"class":80}," opt in build test deploy; ",[36,3812,817],{"class":62},[36,3814,3815,3817,3819,3821],{"class":38,"line":390},[36,3816,93],{"class":69},[36,3818,121],{"class":73},[36,3820,3729],{"class":80},[36,3822,382],{"class":73},[36,3824,3825],{"class":38,"line":395},[36,3826,3827],{"class":62},"    break\n",[36,3829,3830,3832,3834,3837],{"class":38,"line":401},[36,3831,1551],{"class":62},[36,3833,2448],{"class":62},[36,3835,3836],{"class":73}," \"build\"",[36,3838,3839],{"class":42},"   # feeds \"build\" as input → opt=build\n",[15,3841,3843],{"id":3842},"exit-status-the-heart-of-bash-control-flow","Exit Status: The Heart of Bash Control Flow",[24,3845,3846],{"language":26},[28,3847,3849],{"className":30,"code":3848,"language":26,"meta":32,"style":32},"# ── Every command returns an exit status (0-255) ──\n# 0 = success, 1-255 = failure\n# $? = exit status of the last command (SAVE IT IMMEDIATELY — it's overwritten by next command)\n\ngrep \"error\" log.txt\nstatus=$?    # save immediately — any command overwrites $?\nif ((status == 0)); then\n    echo \"found\"\nelif ((status == 1)); then\n    echo \"not found\"\nelif ((status == 2)); then\n    echo \"grep error\"\nfi\n\n# ── Exit codes convention ──\n# 0     success\n# 1     general failure\n# 2     misuse \u002F usage error (shell builtin convention)\n# 126   command found but not executable\n# 127   command not found\n# 128   invalid exit argument (exit 300 → 44, modulo 256)\n# 128+N killed by signal N:\n#   130 = 128+2  (SIGINT, Ctrl-C)\n#   137 = 128+9  (SIGKILL)\n#   143 = 128+15 (SIGTERM)\n\n# ── `exit` wraps to 0-255 ──\nexit 300   # actual exit code: 44 (300 % 256 = 44)\nexit -1    # actual exit code: 255 (-1 % 256 = 255)\n\n# ── Functions: `return` (not `exit`) ──\ncheck_file() {\n    [[ -f \"$1\" ]] && return 0 || return 1\n    # return is like exit but for functions — returns to the caller\n    # return 0 = success, return 1-255 = failure\n    # return without a value uses the last command's exit status\n}\n\n# ── Command lists propagate exit status ──\n# The exit status of a command list is the LAST command's status:\nfalse; true    # exit 0 (true is last)\ntrue; false    # exit 1 (false is last)\n\n# ── `!` negates exit status ──\n! false        # exit 0 (negated 1 → 0)\n! true         # exit 1 (negated 0 → 1)\n",[19,3850,3851,3856,3861,3866,3870,3879,3892,3907,3914,3928,3935,3949,3956,3960,3964,3969,3974,3979,3984,3989,3994,3999,4004,4009,4014,4019,4023,4028,4038,4048,4052,4057,4065,4091,4096,4101,4106,4111,4115,4120,4125,4138,4149,4153,4158,4169],{"__ignoreMap":32},[36,3852,3853],{"class":38,"line":39},[36,3854,3855],{"class":42},"# ── Every command returns an exit status (0-255) ──\n",[36,3857,3858],{"class":38,"line":46},[36,3859,3860],{"class":42},"# 0 = success, 1-255 = failure\n",[36,3862,3863],{"class":38,"line":52},[36,3864,3865],{"class":42},"# $? = exit status of the last command (SAVE IT IMMEDIATELY — it's overwritten by next command)\n",[36,3867,3868],{"class":38,"line":59},[36,3869,56],{"emptyLinePlaceholder":55},[36,3871,3872,3874,3876],{"class":38,"line":90},[36,3873,1823],{"class":65},[36,3875,74],{"class":73},[36,3877,3878],{"class":73}," log.txt\n",[36,3880,3881,3884,3886,3889],{"class":38,"line":102},[36,3882,3883],{"class":80},"status",[36,3885,948],{"class":62},[36,3887,3888],{"class":69},"$?",[36,3890,3891],{"class":42},"    # save immediately — any command overwrites $?\n",[36,3893,3894,3896,3899,3901,3903,3905],{"class":38,"line":108},[36,3895,21],{"class":62},[36,3897,3898],{"class":80}," ((status ",[36,3900,3250],{"class":62},[36,3902,637],{"class":69},[36,3904,698],{"class":80},[36,3906,293],{"class":62},[36,3908,3909,3911],{"class":38,"line":113},[36,3910,93],{"class":69},[36,3912,3913],{"class":73}," \"found\"\n",[36,3915,3916,3918,3920,3922,3924,3926],{"class":38,"line":143},[36,3917,307],{"class":62},[36,3919,3898],{"class":80},[36,3921,3250],{"class":62},[36,3923,179],{"class":69},[36,3925,698],{"class":80},[36,3927,293],{"class":62},[36,3929,3930,3932],{"class":38,"line":158},[36,3931,93],{"class":69},[36,3933,3934],{"class":73}," \"not found\"\n",[36,3936,3937,3939,3941,3943,3945,3947],{"class":38,"line":163},[36,3938,307],{"class":62},[36,3940,3898],{"class":80},[36,3942,3250],{"class":62},[36,3944,185],{"class":69},[36,3946,698],{"class":80},[36,3948,293],{"class":62},[36,3950,3951,3953],{"class":38,"line":168},[36,3952,93],{"class":69},[36,3954,3955],{"class":73}," \"grep error\"\n",[36,3957,3958],{"class":38,"line":209},[36,3959,105],{"class":62},[36,3961,3962],{"class":38,"line":217},[36,3963,56],{"emptyLinePlaceholder":55},[36,3965,3966],{"class":38,"line":222},[36,3967,3968],{"class":42},"# ── Exit codes convention ──\n",[36,3970,3971],{"class":38,"line":227},[36,3972,3973],{"class":42},"# 0     success\n",[36,3975,3976],{"class":38,"line":252},[36,3977,3978],{"class":42},"# 1     general failure\n",[36,3980,3981],{"class":38,"line":260},[36,3982,3983],{"class":42},"# 2     misuse \u002F usage error (shell builtin convention)\n",[36,3985,3986],{"class":38,"line":265},[36,3987,3988],{"class":42},"# 126   command found but not executable\n",[36,3990,3991],{"class":38,"line":270},[36,3992,3993],{"class":42},"# 127   command not found\n",[36,3995,3996],{"class":38,"line":276},[36,3997,3998],{"class":42},"# 128   invalid exit argument (exit 300 → 44, modulo 256)\n",[36,4000,4001],{"class":38,"line":296},[36,4002,4003],{"class":42},"# 128+N killed by signal N:\n",[36,4005,4006],{"class":38,"line":304},[36,4007,4008],{"class":42},"#   130 = 128+2  (SIGINT, Ctrl-C)\n",[36,4010,4011],{"class":38,"line":334},[36,4012,4013],{"class":42},"#   137 = 128+9  (SIGKILL)\n",[36,4015,4016],{"class":38,"line":342},[36,4017,4018],{"class":42},"#   143 = 128+15 (SIGTERM)\n",[36,4020,4021],{"class":38,"line":357},[36,4022,56],{"emptyLinePlaceholder":55},[36,4024,4025],{"class":38,"line":365},[36,4026,4027],{"class":42},"# ── `exit` wraps to 0-255 ──\n",[36,4029,4030,4032,4035],{"class":38,"line":371},[36,4031,512],{"class":69},[36,4033,4034],{"class":69}," 300",[36,4036,4037],{"class":42},"   # actual exit code: 44 (300 % 256 = 44)\n",[36,4039,4040,4042,4045],{"class":38,"line":385},[36,4041,512],{"class":69},[36,4043,4044],{"class":69}," -1",[36,4046,4047],{"class":42},"    # actual exit code: 255 (-1 % 256 = 255)\n",[36,4049,4050],{"class":38,"line":390},[36,4051,56],{"emptyLinePlaceholder":55},[36,4053,4054],{"class":38,"line":395},[36,4055,4056],{"class":42},"# ── Functions: `return` (not `exit`) ──\n",[36,4058,4059,4062],{"class":38,"line":401},[36,4060,4061],{"class":65},"check_file",[36,4063,4064],{"class":80},"() {\n",[36,4066,4067,4069,4071,4073,4075,4077,4079,4082,4084,4086,4089],{"class":38,"line":426},[36,4068,903],{"class":80},[36,4070,476],{"class":62},[36,4072,121],{"class":73},[36,4074,2528],{"class":69},[36,4076,127],{"class":73},[36,4078,647],{"class":80},[36,4080,4081],{"class":62},"return",[36,4083,637],{"class":69},[36,4085,655],{"class":62},[36,4087,4088],{"class":62}," return",[36,4090,1430],{"class":69},[36,4092,4093],{"class":38,"line":434},[36,4094,4095],{"class":42},"    # return is like exit but for functions — returns to the caller\n",[36,4097,4098],{"class":38,"line":1164},[36,4099,4100],{"class":42},"    # return 0 = success, return 1-255 = failure\n",[36,4102,4103],{"class":38,"line":1186},[36,4104,4105],{"class":42},"    # return without a value uses the last command's exit status\n",[36,4107,4108],{"class":38,"line":1191},[36,4109,4110],{"class":80},"}\n",[36,4112,4113],{"class":38,"line":1196},[36,4114,56],{"emptyLinePlaceholder":55},[36,4116,4117],{"class":38,"line":1202},[36,4118,4119],{"class":42},"# ── Command lists propagate exit status ──\n",[36,4121,4122],{"class":38,"line":1231},[36,4123,4124],{"class":42},"# The exit status of a command list is the LAST command's status:\n",[36,4126,4127,4130,4132,4135],{"class":38,"line":1245},[36,4128,4129],{"class":69},"false",[36,4131,81],{"class":80},[36,4133,4134],{"class":69},"true",[36,4136,4137],{"class":42},"    # exit 0 (true is last)\n",[36,4139,4140,4142,4144,4146],{"class":38,"line":1250},[36,4141,4134],{"class":69},[36,4143,81],{"class":80},[36,4145,4129],{"class":69},[36,4147,4148],{"class":42},"    # exit 1 (false is last)\n",[36,4150,4151],{"class":38,"line":1255},[36,4152,56],{"emptyLinePlaceholder":55},[36,4154,4155],{"class":38,"line":1261},[36,4156,4157],{"class":42},"# ── `!` negates exit status ──\n",[36,4159,4160,4163,4166],{"class":38,"line":1271},[36,4161,4162],{"class":62},"!",[36,4164,4165],{"class":69}," false",[36,4167,4168],{"class":42},"        # exit 0 (negated 1 → 0)\n",[36,4170,4171,4173,4176],{"class":38,"line":1282},[36,4172,4162],{"class":62},[36,4174,4175],{"class":69}," true",[36,4177,4178],{"class":42},"         # exit 1 (negated 0 → 1)\n",[15,4180,4182],{"id":4181},"production-pattern-retry-with-backoff","Production Pattern: Retry with Backoff",[24,4184,4185],{"language":26},[28,4186,4188],{"className":30,"code":4187,"language":26,"meta":32,"style":32},"# ── Retry a command with exponential backoff ──\nretry() {\n    local max_attempts=$1 delay=$2 shift 2\n    local attempt=1\n    local status=0\n\n    while ((attempt \u003C= max_attempts)); do\n        \"$@\" && return 0    # success — return 0\n        status=$?           # capture failure status\n        log WARN \"attempt $attempt\u002F$max_attempts failed (exit $status)\"\n        ((attempt \u003C max_attempts)) && sleep \"$delay\"\n        ((delay *= 2))      # exponential backoff: 1, 2, 4, 8, ...\n        ((delay > 60)) && delay=60  # cap at 60s\n        ((attempt++))\n    done\n\n    return \"$status\"        # return the last failure's exit status\n}\n\n# Usage: retry 5 1 curl -s \"$url\" -o \"$file\"\n# Retries up to 5 times with backoff: 1s, 2s, 4s, 8s, 16s\n",[19,4189,4190,4195,4202,4225,4237,4248,4252,4268,4286,4298,4326,4346,4362,4382,4391,4395,4399,4413,4417,4421,4426],{"__ignoreMap":32},[36,4191,4192],{"class":38,"line":39},[36,4193,4194],{"class":42},"# ── Retry a command with exponential backoff ──\n",[36,4196,4197,4200],{"class":38,"line":46},[36,4198,4199],{"class":65},"retry",[36,4201,4064],{"class":80},[36,4203,4204,4207,4210,4212,4214,4217,4219,4222],{"class":38,"line":52},[36,4205,4206],{"class":62},"    local",[36,4208,4209],{"class":80}," max_attempts",[36,4211,948],{"class":62},[36,4213,2528],{"class":2785},[36,4215,4216],{"class":80}," delay",[36,4218,948],{"class":62},[36,4220,4221],{"class":2785},"$2",[36,4223,4224],{"class":80}," shift 2\n",[36,4226,4227,4229,4232,4234],{"class":38,"line":59},[36,4228,4206],{"class":62},[36,4230,4231],{"class":80}," attempt",[36,4233,948],{"class":62},[36,4235,4236],{"class":69},"1\n",[36,4238,4239,4241,4244,4246],{"class":38,"line":90},[36,4240,4206],{"class":62},[36,4242,4243],{"class":80}," status",[36,4245,948],{"class":62},[36,4247,1333],{"class":69},[36,4249,4250],{"class":38,"line":102},[36,4251,56],{"emptyLinePlaceholder":55},[36,4253,4254,4257,4260,4263,4266],{"class":38,"line":108},[36,4255,4256],{"class":62},"    while",[36,4258,4259],{"class":80}," ((attempt ",[36,4261,4262],{"class":62},"\u003C=",[36,4264,4265],{"class":80}," max_attempts)); ",[36,4267,817],{"class":62},[36,4269,4270,4273,4275,4277,4279,4281,4283],{"class":38,"line":113},[36,4271,4272],{"class":65},"        \"",[36,4274,1030],{"class":69},[36,4276,127],{"class":65},[36,4278,543],{"class":80},[36,4280,4081],{"class":62},[36,4282,637],{"class":69},[36,4284,4285],{"class":42},"    # success — return 0\n",[36,4287,4288,4291,4293,4295],{"class":38,"line":143},[36,4289,4290],{"class":80},"        status",[36,4292,948],{"class":62},[36,4294,3888],{"class":69},[36,4296,4297],{"class":42},"           # capture failure status\n",[36,4299,4300,4303,4306,4309,4312,4315,4318,4321,4323],{"class":38,"line":158},[36,4301,4302],{"class":65},"        log",[36,4304,4305],{"class":73}," WARN",[36,4307,4308],{"class":73}," \"attempt ",[36,4310,4311],{"class":80},"$attempt",[36,4313,4314],{"class":73},"\u002F",[36,4316,4317],{"class":80},"$max_attempts",[36,4319,4320],{"class":73}," failed (exit ",[36,4322,379],{"class":80},[36,4324,4325],{"class":73},")\"\n",[36,4327,4328,4331,4333,4336,4339,4341,4344],{"class":38,"line":163},[36,4329,4330],{"class":80},"        ((attempt ",[36,4332,1081],{"class":62},[36,4334,4335],{"class":80}," max_attempts)) && ",[36,4337,4338],{"class":65},"sleep",[36,4340,121],{"class":73},[36,4342,4343],{"class":80},"$delay",[36,4345,382],{"class":73},[36,4347,4348,4351,4354,4356,4359],{"class":38,"line":168},[36,4349,4350],{"class":80},"        ((delay ",[36,4352,4353],{"class":62},"*=",[36,4355,185],{"class":69},[36,4357,4358],{"class":80},"))      ",[36,4360,4361],{"class":42},"# exponential backoff: 1, 2, 4, 8, ...\n",[36,4363,4364,4366,4368,4371,4374,4376,4379],{"class":38,"line":209},[36,4365,4350],{"class":80},[36,4367,198],{"class":62},[36,4369,4370],{"class":69}," 60",[36,4372,4373],{"class":80},")) && delay",[36,4375,948],{"class":62},[36,4377,4378],{"class":73},"60",[36,4380,4381],{"class":42},"  # cap at 60s\n",[36,4383,4384,4387,4389],{"class":38,"line":217},[36,4385,4386],{"class":80},"        ((attempt",[36,4388,1090],{"class":62},[36,4390,1279],{"class":80},[36,4392,4393],{"class":38,"line":222},[36,4394,3422],{"class":62},[36,4396,4397],{"class":38,"line":227},[36,4398,56],{"emptyLinePlaceholder":55},[36,4400,4401,4404,4406,4408,4410],{"class":38,"line":252},[36,4402,4403],{"class":62},"    return",[36,4405,121],{"class":73},[36,4407,379],{"class":80},[36,4409,127],{"class":73},[36,4411,4412],{"class":42},"        # return the last failure's exit status\n",[36,4414,4415],{"class":38,"line":260},[36,4416,4110],{"class":80},[36,4418,4419],{"class":38,"line":265},[36,4420,56],{"emptyLinePlaceholder":55},[36,4422,4423],{"class":38,"line":270},[36,4424,4425],{"class":42},"# Usage: retry 5 1 curl -s \"$url\" -o \"$file\"\n",[36,4427,4428],{"class":38,"line":276},[36,4429,4430],{"class":42},"# Retries up to 5 times with backoff: 1s, 2s, 4s, 8s, 16s\n",[15,4432,4434],{"id":4433},"tips-tricks","💡 Tips & Tricks",[24,4436,4437],{"language":26},[28,4438,4440],{"className":30,"code":4439,"language":26,"meta":32,"style":32},"# ── `while true` for infinite loops with a break condition ──\nwhile true; do\n    response=$(curl -s \"$url\")\n    [[ \"$response\" == *\"ready\"* ]] && break\n    sleep 5\ndone\n\n# ── Process all files with null-delimited find (handles ALL filenames) ──\nwhile IFS= read -r -d '' file; do\n    process \"$file\"\ndone \u003C \u003C(find . -type f -print0)\n\n# ── Loop with index using C-style for ──\narr=(\"a\" \"b\" \"c\")\nfor ((i = 0; i \u003C ${#arr[@]}; i++)); do\n    printf '%d: %s\\n' \"$i\" \"${arr[i]}\"\ndone\n\n# ── Loop with index and value (for in + !array[@]) ──\nfor i in \"${!arr[@]}\"; do    # ${!arr[@]} = indices of array\n    printf '%d: %s\\n' \"$i\" \"${arr[i]}\"\ndone\n\n# ── Batch processing with chunked iteration ──\nitems=($(seq 1 100))\nbatch_size=10\nfor ((i = 0; i \u003C ${#items[@]}; i += batch_size)); do\n    batch=(\"${items[@]:i:batch_size}\")   # slice the array\n    printf 'batch: %s\\n' \"${batch[*]}\"\ndone\n",[19,4441,4442,4447,4457,4481,4506,4513,4517,4521,4526,4548,4559,4581,4585,4590,4610,4644,4664,4668,4672,4677,4704,4722,4726,4730,4735,4754,4764,4797,4835,4854],{"__ignoreMap":32},[36,4443,4444],{"class":38,"line":39},[36,4445,4446],{"class":42},"# ── `while true` for infinite loops with a break condition ──\n",[36,4448,4449,4451,4453,4455],{"class":38,"line":46},[36,4450,1307],{"class":62},[36,4452,4175],{"class":69},[36,4454,81],{"class":80},[36,4456,817],{"class":62},[36,4458,4459,4462,4464,4467,4470,4472,4474,4477,4479],{"class":38,"line":52},[36,4460,4461],{"class":80},"    response",[36,4463,948],{"class":62},[36,4465,4466],{"class":80},"$(",[36,4468,4469],{"class":65},"curl",[36,4471,1466],{"class":69},[36,4473,121],{"class":73},[36,4475,4476],{"class":80},"$url",[36,4478,127],{"class":73},[36,4480,963],{"class":80},[36,4482,4483,4485,4487,4490,4492,4494,4497,4500,4502,4504],{"class":38,"line":59},[36,4484,903],{"class":80},[36,4486,127],{"class":73},[36,4488,4489],{"class":80},"$response",[36,4491,127],{"class":73},[36,4493,3315],{"class":62},[36,4495,4496],{"class":62}," *",[36,4498,4499],{"class":73},"\"ready\"",[36,4501,2046],{"class":62},[36,4503,647],{"class":80},[36,4505,1296],{"class":62},[36,4507,4508,4510],{"class":38,"line":90},[36,4509,1427],{"class":65},[36,4511,4512],{"class":69}," 5\n",[36,4514,4515],{"class":38,"line":102},[36,4516,833],{"class":62},[36,4518,4519],{"class":38,"line":108},[36,4520,56],{"emptyLinePlaceholder":55},[36,4522,4523],{"class":38,"line":113},[36,4524,4525],{"class":42},"# ── Process all files with null-delimited find (handles ALL filenames) ──\n",[36,4527,4528,4530,4532,4534,4536,4538,4540,4542,4544,4546],{"class":38,"line":143},[36,4529,1307],{"class":62},[36,4531,1607],{"class":80},[36,4533,948],{"class":62},[36,4535,1522],{"class":69},[36,4537,1525],{"class":69},[36,4539,1850],{"class":69},[36,4541,1853],{"class":73},[36,4543,1856],{"class":73},[36,4545,81],{"class":80},[36,4547,817],{"class":62},[36,4549,4550,4553,4555,4557],{"class":38,"line":158},[36,4551,4552],{"class":65},"    process",[36,4554,121],{"class":73},[36,4556,868],{"class":80},[36,4558,382],{"class":73},[36,4560,4561,4563,4565,4567,4569,4571,4574,4577,4579],{"class":38,"line":163},[36,4562,1551],{"class":62},[36,4564,1554],{"class":62},[36,4566,1820],{"class":73},[36,4568,1892],{"class":65},[36,4570,1895],{"class":73},[36,4572,4573],{"class":69},"-type",[36,4575,4576],{"class":73}," f ",[36,4578,1904],{"class":69},[36,4580,963],{"class":73},[36,4582,4583],{"class":38,"line":168},[36,4584,56],{"emptyLinePlaceholder":55},[36,4586,4587],{"class":38,"line":209},[36,4588,4589],{"class":42},"# ── Loop with index using C-style for ──\n",[36,4591,4592,4595,4597,4599,4602,4605,4608],{"class":38,"line":217},[36,4593,4594],{"class":80},"arr",[36,4596,948],{"class":62},[36,4598,951],{"class":80},[36,4600,4601],{"class":73},"\"a\"",[36,4603,4604],{"class":73}," \"b\"",[36,4606,4607],{"class":73}," \"c\"",[36,4609,963],{"class":80},[36,4611,4612,4614,4616,4618,4620,4622,4624,4627,4630,4633,4635,4638,4640,4642],{"class":38,"line":222},[36,4613,780],{"class":62},[36,4615,1071],{"class":80},[36,4617,948],{"class":62},[36,4619,637],{"class":69},[36,4621,1078],{"class":80},[36,4623,1081],{"class":62},[36,4625,4626],{"class":80}," ${",[36,4628,4629],{"class":62},"#",[36,4631,4632],{"class":80},"arr[",[36,4634,982],{"class":62},[36,4636,4637],{"class":80},"]}; i",[36,4639,1090],{"class":62},[36,4641,698],{"class":80},[36,4643,817],{"class":62},[36,4645,4646,4648,4651,4653,4655,4657,4659,4661],{"class":38,"line":227},[36,4647,1167],{"class":69},[36,4649,4650],{"class":73}," '%d: %s\\n'",[36,4652,121],{"class":73},[36,4654,1104],{"class":80},[36,4656,127],{"class":73},[36,4658,974],{"class":73},[36,4660,4594],{"class":80},[36,4662,4663],{"class":73},"[i]}\"\n",[36,4665,4666],{"class":38,"line":252},[36,4667,833],{"class":62},[36,4669,4670],{"class":38,"line":260},[36,4671,56],{"emptyLinePlaceholder":55},[36,4673,4674],{"class":38,"line":265},[36,4675,4676],{"class":42},"# ── Loop with index and value (for in + !array[@]) ──\n",[36,4678,4679,4681,4683,4685,4687,4689,4691,4693,4695,4697,4699,4701],{"class":38,"line":270},[36,4680,780],{"class":62},[36,4682,3230],{"class":80},[36,4684,803],{"class":62},[36,4686,974],{"class":73},[36,4688,4162],{"class":62},[36,4690,4594],{"class":80},[36,4692,979],{"class":73},[36,4694,982],{"class":62},[36,4696,985],{"class":73},[36,4698,81],{"class":80},[36,4700,990],{"class":62},[36,4702,4703],{"class":42},"    # ${!arr[@]} = indices of array\n",[36,4705,4706,4708,4710,4712,4714,4716,4718,4720],{"class":38,"line":276},[36,4707,1167],{"class":69},[36,4709,4650],{"class":73},[36,4711,121],{"class":73},[36,4713,1104],{"class":80},[36,4715,127],{"class":73},[36,4717,974],{"class":73},[36,4719,4594],{"class":80},[36,4721,4663],{"class":73},[36,4723,4724],{"class":38,"line":296},[36,4725,833],{"class":62},[36,4727,4728],{"class":38,"line":304},[36,4729,56],{"emptyLinePlaceholder":55},[36,4731,4732],{"class":38,"line":334},[36,4733,4734],{"class":42},"# ── Batch processing with chunked iteration ──\n",[36,4736,4737,4740,4742,4745,4748,4750,4752],{"class":38,"line":342},[36,4738,4739],{"class":80},"items",[36,4741,948],{"class":62},[36,4743,4744],{"class":80},"($(",[36,4746,4747],{"class":65},"seq",[36,4749,179],{"class":69},[36,4751,1217],{"class":69},[36,4753,1279],{"class":80},[36,4755,4756,4759,4761],{"class":38,"line":357},[36,4757,4758],{"class":80},"batch_size",[36,4760,948],{"class":62},[36,4762,4763],{"class":73},"10\n",[36,4765,4766,4768,4770,4772,4774,4776,4778,4780,4782,4785,4787,4790,4792,4795],{"class":38,"line":365},[36,4767,780],{"class":62},[36,4769,1071],{"class":80},[36,4771,948],{"class":62},[36,4773,637],{"class":69},[36,4775,1078],{"class":80},[36,4777,1081],{"class":62},[36,4779,4626],{"class":80},[36,4781,4629],{"class":62},[36,4783,4784],{"class":80},"items[",[36,4786,982],{"class":62},[36,4788,4789],{"class":80},"]}; i ",[36,4791,1222],{"class":62},[36,4793,4794],{"class":80}," batch_size)); ",[36,4796,817],{"class":62},[36,4798,4799,4802,4804,4806,4808,4810,4812,4814,4816,4819,4822,4824,4826,4829,4832],{"class":38,"line":371},[36,4800,4801],{"class":80},"    batch",[36,4803,948],{"class":62},[36,4805,951],{"class":80},[36,4807,2823],{"class":73},[36,4809,4739],{"class":80},[36,4811,979],{"class":73},[36,4813,982],{"class":62},[36,4815,2796],{"class":73},[36,4817,4818],{"class":62},":",[36,4820,4821],{"class":80},"i",[36,4823,4818],{"class":62},[36,4825,4758],{"class":80},[36,4827,4828],{"class":73},"}\"",[36,4830,4831],{"class":80},")   ",[36,4833,4834],{"class":42},"# slice the array\n",[36,4836,4837,4839,4842,4844,4847,4849,4851],{"class":38,"line":385},[36,4838,1167],{"class":69},[36,4840,4841],{"class":73}," 'batch: %s\\n'",[36,4843,974],{"class":73},[36,4845,4846],{"class":80},"batch",[36,4848,979],{"class":73},[36,4850,2046],{"class":62},[36,4852,4853],{"class":73},"]}\"\n",[36,4855,4856],{"class":38,"line":390},[36,4857,833],{"class":62},[15,4859,4861],{"id":4860},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[24,4863,4864],{"language":26},[28,4865,4867],{"className":30,"code":4866,"language":26,"meta":32,"style":32},"# ── `for f in *.txt` passes literal \"*.txt\" if no match ──\n# Without nullglob: for f in *.txt → f=\"*.txt\" (literal, one iteration)\n# With nullglob:    for f in *.txt → zero iterations (empty result)\n# With failglob:    for f in *.txt → bash: no match: *.txt (error, script aborts)\n# Choose: nullglob (safe, no iteration) for loops. failglob for one-shot globs.\n\n# ── `until` is `while not` (easy to confuse) ──\n# while condition  → loop while TRUE\n# until condition  → loop while FALSE (i.e., until it becomes true)\nuntil [[ -f \u002Ftmp\u002Fready ]]; do sleep 1; done  # wait until file appears\n\n# ── `exit` in a subshell doesn't exit the script ──\necho \"before\"\n(echo \"in subshell\"; exit 1)   # subshell exits 1, but...\necho \"after\"                    # prints! The main script continues.\n# To propagate: check the subshell's status:\n( exit 1 ) || { echo \"subshell failed\" >&2; exit 1; }\n\n# ── `$?` is volatile — save it immediately ──\ncmd\nstatus=$?    # ← save NOW\necho \"status: $status\"\nother_cmd\necho \"$?\"     # this is other_cmd's status, NOT cmd's!\n\n# ── `while read` without IFS= and -r (silent data corruption) ──\n# ❌ for line in $(cat file) — word splits, breaks on spaces\n# ❌ while read line        — trims whitespace (IFS=default), interprets backslashes (no -r)\n# ✅ while IFS= read -r line — preserves everything (canonical)\n\n# ── case patterns are globs, not regex ──\ncase \"$str\" in\n    .*\\.txt)  echo \"hidden txt\" ;;  # glob: . (literal dot) * (any chars) .txt\n    *)        echo \"other\" ;;\nesac\n# For regex matching, use [[ $str =~ regex ]], not case.\n",[19,4868,4869,4874,4879,4884,4889,4894,4898,4903,4908,4913,4938,4942,4947,4954,4974,4984,4989,5020,5024,5029,5034,5045,5056,5061,5074,5078,5083,5088,5093,5098,5102,5107,5120,5146,5156,5160],{"__ignoreMap":32},[36,4870,4871],{"class":38,"line":39},[36,4872,4873],{"class":42},"# ── `for f in *.txt` passes literal \"*.txt\" if no match ──\n",[36,4875,4876],{"class":38,"line":46},[36,4877,4878],{"class":42},"# Without nullglob: for f in *.txt → f=\"*.txt\" (literal, one iteration)\n",[36,4880,4881],{"class":38,"line":52},[36,4882,4883],{"class":42},"# With nullglob:    for f in *.txt → zero iterations (empty result)\n",[36,4885,4886],{"class":38,"line":59},[36,4887,4888],{"class":42},"# With failglob:    for f in *.txt → bash: no match: *.txt (error, script aborts)\n",[36,4890,4891],{"class":38,"line":90},[36,4892,4893],{"class":42},"# Choose: nullglob (safe, no iteration) for loops. failglob for one-shot globs.\n",[36,4895,4896],{"class":38,"line":102},[36,4897,56],{"emptyLinePlaceholder":55},[36,4899,4900],{"class":38,"line":108},[36,4901,4902],{"class":42},"# ── `until` is `while not` (easy to confuse) ──\n",[36,4904,4905],{"class":38,"line":113},[36,4906,4907],{"class":42},"# while condition  → loop while TRUE\n",[36,4909,4910],{"class":38,"line":143},[36,4911,4912],{"class":42},"# until condition  → loop while FALSE (i.e., until it becomes true)\n",[36,4914,4915,4917,4919,4921,4924,4926,4929,4931,4933,4935],{"class":38,"line":158},[36,4916,1311],{"class":62},[36,4918,2782],{"class":80},[36,4920,476],{"class":62},[36,4922,4923],{"class":80}," \u002Ftmp\u002Fready ]]; ",[36,4925,990],{"class":62},[36,4927,4928],{"class":65}," sleep",[36,4930,179],{"class":69},[36,4932,81],{"class":80},[36,4934,1551],{"class":62},[36,4936,4937],{"class":42},"  # wait until file appears\n",[36,4939,4940],{"class":38,"line":163},[36,4941,56],{"emptyLinePlaceholder":55},[36,4943,4944],{"class":38,"line":168},[36,4945,4946],{"class":42},"# ── `exit` in a subshell doesn't exit the script ──\n",[36,4948,4949,4951],{"class":38,"line":209},[36,4950,482],{"class":69},[36,4952,4953],{"class":73}," \"before\"\n",[36,4955,4956,4958,4960,4963,4965,4967,4969,4971],{"class":38,"line":217},[36,4957,951],{"class":80},[36,4959,482],{"class":69},[36,4961,4962],{"class":73}," \"in subshell\"",[36,4964,81],{"class":80},[36,4966,512],{"class":69},[36,4968,179],{"class":69},[36,4970,4831],{"class":80},[36,4972,4973],{"class":42},"# subshell exits 1, but...\n",[36,4975,4976,4978,4981],{"class":38,"line":222},[36,4977,482],{"class":69},[36,4979,4980],{"class":73}," \"after\"",[36,4982,4983],{"class":42},"                    # prints! The main script continues.\n",[36,4985,4986],{"class":38,"line":227},[36,4987,4988],{"class":42},"# To propagate: check the subshell's status:\n",[36,4990,4991,4994,4996,4998,5001,5003,5005,5007,5010,5012,5014,5016,5018],{"class":38,"line":252},[36,4992,4993],{"class":80},"( ",[36,4995,512],{"class":69},[36,4997,179],{"class":69},[36,4999,5000],{"class":80}," ) ",[36,5002,446],{"class":62},[36,5004,499],{"class":80},[36,5006,482],{"class":69},[36,5008,5009],{"class":73}," \"subshell failed\"",[36,5011,507],{"class":62},[36,5013,81],{"class":80},[36,5015,512],{"class":69},[36,5017,179],{"class":69},[36,5019,517],{"class":80},[36,5021,5022],{"class":38,"line":260},[36,5023,56],{"emptyLinePlaceholder":55},[36,5025,5026],{"class":38,"line":265},[36,5027,5028],{"class":42},"# ── `$?` is volatile — save it immediately ──\n",[36,5030,5031],{"class":38,"line":270},[36,5032,5033],{"class":65},"cmd\n",[36,5035,5036,5038,5040,5042],{"class":38,"line":276},[36,5037,3883],{"class":80},[36,5039,948],{"class":62},[36,5041,3888],{"class":69},[36,5043,5044],{"class":42},"    # ← save NOW\n",[36,5046,5047,5049,5052,5054],{"class":38,"line":296},[36,5048,482],{"class":69},[36,5050,5051],{"class":73}," \"status: ",[36,5053,379],{"class":80},[36,5055,382],{"class":73},[36,5057,5058],{"class":38,"line":304},[36,5059,5060],{"class":65},"other_cmd\n",[36,5062,5063,5065,5067,5069,5071],{"class":38,"line":334},[36,5064,482],{"class":69},[36,5066,121],{"class":73},[36,5068,3888],{"class":69},[36,5070,127],{"class":73},[36,5072,5073],{"class":42},"     # this is other_cmd's status, NOT cmd's!\n",[36,5075,5076],{"class":38,"line":342},[36,5077,56],{"emptyLinePlaceholder":55},[36,5079,5080],{"class":38,"line":357},[36,5081,5082],{"class":42},"# ── `while read` without IFS= and -r (silent data corruption) ──\n",[36,5084,5085],{"class":38,"line":365},[36,5086,5087],{"class":42},"# ❌ for line in $(cat file) — word splits, breaks on spaces\n",[36,5089,5090],{"class":38,"line":371},[36,5091,5092],{"class":42},"# ❌ while read line        — trims whitespace (IFS=default), interprets backslashes (no -r)\n",[36,5094,5095],{"class":38,"line":385},[36,5096,5097],{"class":42},"# ✅ while IFS= read -r line — preserves everything (canonical)\n",[36,5099,5100],{"class":38,"line":390},[36,5101,56],{"emptyLinePlaceholder":55},[36,5103,5104],{"class":38,"line":395},[36,5105,5106],{"class":42},"# ── case patterns are globs, not regex ──\n",[36,5108,5109,5111,5113,5116,5118],{"class":38,"line":401},[36,5110,2506],{"class":62},[36,5112,121],{"class":73},[36,5114,5115],{"class":80},"$str",[36,5117,127],{"class":73},[36,5119,2533],{"class":62},[36,5121,5122,5125,5127,5130,5133,5135,5138,5141,5143],{"class":38,"line":426},[36,5123,5124],{"class":2538},"    .",[36,5126,2046],{"class":62},[36,5128,5129],{"class":69},"\\.",[36,5131,5132],{"class":2538},"txt",[36,5134,2586],{"class":62},[36,5136,5137],{"class":69},"  echo",[36,5139,5140],{"class":73}," \"hidden txt\"",[36,5142,2740],{"class":80},[36,5144,5145],{"class":42},"# glob: . (literal dot) * (any chars) .txt\n",[36,5147,5148,5150,5152,5154],{"class":38,"line":434},[36,5149,2748],{"class":62},[36,5151,2546],{"class":69},[36,5153,2754],{"class":73},[36,5155,2757],{"class":80},[36,5157,5158],{"class":38,"line":1164},[36,5159,2664],{"class":62},[36,5161,5162],{"class":38,"line":1186},[36,5163,5164],{"class":42},"# For regex matching, use [[ $str =~ regex ]], not case.\n",[15,5166,5168],{"id":5167},"quick-quiz","🧠 Quick Quiz",[5170,5171,5172],"p",{},"Why does this loop never end?",[24,5174,5175],{"language":26},[28,5176,5178],{"className":30,"code":5177,"language":26,"meta":32,"style":32},"i=0\nwhile ((i \u003C 10)); do\n    echo \"$i\"\ndone\n",[19,5179,5180,5188,5202,5212],{"__ignoreMap":32},[36,5181,5182,5184,5186],{"class":38,"line":39},[36,5183,4821],{"class":80},[36,5185,948],{"class":62},[36,5187,1333],{"class":73},[36,5189,5190,5192,5194,5196,5198,5200],{"class":38,"line":46},[36,5191,1307],{"class":62},[36,5193,1071],{"class":80},[36,5195,1081],{"class":62},[36,5197,1140],{"class":69},[36,5199,698],{"class":80},[36,5201,817],{"class":62},[36,5203,5204,5206,5208,5210],{"class":38,"line":52},[36,5205,93],{"class":69},[36,5207,121],{"class":73},[36,5209,1104],{"class":80},[36,5211,382],{"class":73},[36,5213,5214],{"class":38,"line":59},[36,5215,833],{"class":62},[5217,5218,5219,5223,5235,5245,5300],"details",{},[5220,5221,5222],"summary",{},"Answer",[5170,5224,5225,5227,5228,5231,5232,5234],{},[19,5226,4821],{}," is never incremented inside the loop. ",[19,5229,5230],{},"((i \u003C 10))"," is always true (0 \u003C 10) because ",[19,5233,4821],{}," stays 0 forever. Infinite loop.",[5170,5236,5237,5241,5242,5244],{},[5238,5239,5240],"strong",{},"Fix",": increment ",[19,5243,4821],{}," inside the loop body:",[24,5246,5247],{"language":26},[28,5248,5250],{"className":30,"code":5249,"language":26,"meta":32,"style":32},"i=0\nwhile ((i \u003C 10)); do\n    echo \"$i\"\n    ((i++))    # ← missing increment\ndone\n",[19,5251,5252,5260,5274,5284,5296],{"__ignoreMap":32},[36,5253,5254,5256,5258],{"class":38,"line":39},[36,5255,4821],{"class":80},[36,5257,948],{"class":62},[36,5259,1333],{"class":73},[36,5261,5262,5264,5266,5268,5270,5272],{"class":38,"line":46},[36,5263,1307],{"class":62},[36,5265,1071],{"class":80},[36,5267,1081],{"class":62},[36,5269,1140],{"class":69},[36,5271,698],{"class":80},[36,5273,817],{"class":62},[36,5275,5276,5278,5280,5282],{"class":38,"line":52},[36,5277,93],{"class":69},[36,5279,121],{"class":73},[36,5281,1104],{"class":80},[36,5283,382],{"class":73},[36,5285,5286,5289,5291,5293],{"class":38,"line":59},[36,5287,5288],{"class":80},"    ((i",[36,5290,1090],{"class":62},[36,5292,2291],{"class":80},[36,5294,5295],{"class":42},"# ← missing increment\n",[36,5297,5298],{"class":38,"line":90},[36,5299,833],{"class":62},[5170,5301,5302,5305,5306,5308,5309,5311],{},[5238,5303,5304],{},"The lesson",": ",[19,5307,1307],{}," checks the condition each iteration, but if the condition's variables never change, the loop never exits. Always ensure the loop body modifies the condition variable (or has a ",[19,5310,3209],{},").",[5313,5314,5315],"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 .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}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}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 .svAP2, html code.shiki .svAP2{--shiki-default:#032F62;--shiki-github-dark:#DBEDFF}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":32,"searchDepth":46,"depth":46,"links":5317},[5318,5320,5322,5324,5326,5328,5330,5331,5333,5335,5337,5338,5339,5340,5341],{"id":17,"depth":46,"text":5319},"if: It's All About Exit Status",{"id":439,"depth":46,"text":5321},"&& \u002F ||: Short-Circuit Composition",{"id":777,"depth":46,"text":5323},"for Loops: List and C-Style",{"id":1304,"depth":46,"text":5325},"while and until",{"id":1560,"depth":46,"text":5327},"while IFS= read -r: The Canonical Line Reader",{"id":2078,"depth":46,"text":5329},"Anti-Pattern: for line in $(cat file)",{"id":2222,"depth":46,"text":2223},{"id":2503,"depth":46,"text":5332},"case: Glob-Based Dispatch",{"id":3206,"depth":46,"text":5334},"break and continue",{"id":3517,"depth":46,"text":5336},"select: Interactive Menus",{"id":3842,"depth":46,"text":3843},{"id":4181,"depth":46,"text":4182},{"id":4433,"depth":46,"text":4434},{"id":4860,"depth":46,"text":4861},{"id":5167,"depth":46,"text":5168},"Deep-dive into Bash control flow: if\u002Felif\u002Felse with command exit status, loop variants (for\u002Fwhile\u002Funtil\u002FC-style), while read -r line-by-line internals, case glob dispatch, and select menu mechanics. Code-first reference with production patterns.","md",{},"\u002Fbash\u002F04-control-flow",{"title":5,"description":5342},"bash\u002F04-control-flow","1QcDphJZcJ5hJRMuQzJ08uIZEo4GZMyn2ag0WTWRcO4",1789924644816]