[{"data":1,"prerenderedAt":4552},["ShallowReactive",2],{"page-\u002Fbash\u002F08-processes-and-signals":3},{"id":4,"title":5,"body":6,"description":4545,"extension":4546,"meta":4547,"navigation":56,"path":4548,"seo":4549,"stem":4550,"__hash__":4551},"content\u002Fbash\u002F08-processes-and-signals.md","Bash 08 — Process Management, Signal Handling & Parallel Execution",{"type":7,"value":8,"toc":4523},"minimark",[9,14,19,381,391,802,809,1028,1032,1276,1283,1776,1780,2224,2231,2605,2609,2878,2885,3272,3286,3453,3457,3693,3697,4191,4195,4350,4354,4362,4441,4519],[10,11,13],"h1",{"id":12},"_08-process-management-signal-handling-parallel-execution","08 — Process Management, Signal Handling & Parallel Execution",[15,16,18],"h2",{"id":17},"process-lifecycle-foreground-background-subshell","Process Lifecycle: Foreground, Background, Subshell",[20,21,23],"code-wrapper",{"language":22},"bash",[24,25,29],"pre",{"className":26,"code":27,"language":22,"meta":28,"style":28},"language-bash shiki shiki-themes github-light github-dark","# ── Foreground: blocks the terminal until the command finishes ──\n.\u002Flong_running.sh    # shell waits for it to exit\n\n# ── Background: returns immediately, command continues ──\n.\u002Flong_running.sh &\n# [1] 12345    ← job number 1, PID 12345\n# The shell prints job number and PID, then returns to the prompt.\n\n# ── Subshell: a child process that's a copy of the current shell ──\n(                    # ( starts a subshell (fork)\n    cd \u002Ftmp          # subshell's CWD changes — does NOT affect parent\n    echo \"in $(pwd)\"  # \u002Ftmp\n)\necho \"parent: $(pwd)\"  # parent's CWD unchanged (subshell didn't leak)\n\n# ── Command substitution is also a subshell ──\nx=before\noutput=$(x=after; echo \"$x\")   # subshell: x is set to \"after\"\necho \"$output\"                 # after\necho \"$x\"                      # before — subshell's x didn't leak\n\n# ── Process substitution runs in a subshell too ──\ndiff \u003C(sort file1) \u003C(sort file2)   # sort runs in subshells, output exposed as fds\n\n# ── Job control ──\n.\u002Fjob1.sh &        # background job 1\n.\u002Fjob2.sh &        # background job 2\njobs               # list all background jobs: [1]- Running  .\u002Fjob1.sh & [2]+ Running  .\u002Fjob2.sh &\nfg %1              # bring job 1 to foreground (blocks until done or Ctrl-Z)\nbg %1              # resume job 1 in background (if it was stopped with Ctrl-Z)\nkill %1            # send SIGTERM to job 1\nkill %2            # send SIGTERM to job 2\nwait               # wait for all background jobs to finish\n","",[30,31,32,41,51,58,64,73,79,85,90,96,105,119,137,143,159,164,170,183,219,234,248,253,259,284,289,295,307,318,327,339,350,361,372],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","# ── Foreground: blocks the terminal until the command finishes ──\n",[33,42,44,48],{"class":35,"line":43},2,[33,45,47],{"class":46},"sIsaT",".\u002Flong_running.sh",[33,49,50],{"class":39},"    # shell waits for it to exit\n",[33,52,54],{"class":35,"line":53},3,[33,55,57],{"emptyLinePlaceholder":56},true,"\n",[33,59,61],{"class":35,"line":60},4,[33,62,63],{"class":39},"# ── Background: returns immediately, command continues ──\n",[33,65,67,69],{"class":35,"line":66},5,[33,68,47],{"class":46},[33,70,72],{"class":71},"ssxIu"," &\n",[33,74,76],{"class":35,"line":75},6,[33,77,78],{"class":39},"# [1] 12345    ← job number 1, PID 12345\n",[33,80,82],{"class":35,"line":81},7,[33,83,84],{"class":39},"# The shell prints job number and PID, then returns to the prompt.\n",[33,86,88],{"class":35,"line":87},8,[33,89,57],{"emptyLinePlaceholder":56},[33,91,93],{"class":35,"line":92},9,[33,94,95],{"class":39},"# ── Subshell: a child process that's a copy of the current shell ──\n",[33,97,99,102],{"class":35,"line":98},10,[33,100,101],{"class":71},"(                    ",[33,103,104],{"class":39},"# ( starts a subshell (fork)\n",[33,106,108,112,116],{"class":35,"line":107},11,[33,109,111],{"class":110},"snvgF","    cd",[33,113,115],{"class":114},"sJ6F3"," \u002Ftmp",[33,117,118],{"class":39},"          # subshell's CWD changes — does NOT affect parent\n",[33,120,122,125,128,131,134],{"class":35,"line":121},12,[33,123,124],{"class":110},"    echo",[33,126,127],{"class":114}," \"in $(",[33,129,130],{"class":110},"pwd",[33,132,133],{"class":114},")\"",[33,135,136],{"class":39},"  # \u002Ftmp\n",[33,138,140],{"class":35,"line":139},13,[33,141,142],{"class":71},")\n",[33,144,146,149,152,154,156],{"class":35,"line":145},14,[33,147,148],{"class":110},"echo",[33,150,151],{"class":114}," \"parent: $(",[33,153,130],{"class":110},[33,155,133],{"class":114},[33,157,158],{"class":39},"  # parent's CWD unchanged (subshell didn't leak)\n",[33,160,162],{"class":35,"line":161},15,[33,163,57],{"emptyLinePlaceholder":56},[33,165,167],{"class":35,"line":166},16,[33,168,169],{"class":39},"# ── Command substitution is also a subshell ──\n",[33,171,173,176,180],{"class":35,"line":172},17,[33,174,175],{"class":71},"x",[33,177,179],{"class":178},"svdQ7","=",[33,181,182],{"class":114},"before\n",[33,184,186,189,191,194,196,199,202,204,207,210,213,216],{"class":35,"line":185},18,[33,187,188],{"class":71},"output",[33,190,179],{"class":178},[33,192,193],{"class":71},"$(x",[33,195,179],{"class":178},[33,197,198],{"class":114},"after",[33,200,201],{"class":71},"; ",[33,203,148],{"class":110},[33,205,206],{"class":114}," \"",[33,208,209],{"class":71},"$x",[33,211,212],{"class":114},"\"",[33,214,215],{"class":71},")   ",[33,217,218],{"class":39},"# subshell: x is set to \"after\"\n",[33,220,222,224,226,229,231],{"class":35,"line":221},19,[33,223,148],{"class":110},[33,225,206],{"class":114},[33,227,228],{"class":71},"$output",[33,230,212],{"class":114},[33,232,233],{"class":39},"                 # after\n",[33,235,237,239,241,243,245],{"class":35,"line":236},20,[33,238,148],{"class":110},[33,240,206],{"class":114},[33,242,209],{"class":71},[33,244,212],{"class":114},[33,246,247],{"class":39},"                      # before — subshell's x didn't leak\n",[33,249,251],{"class":35,"line":250},21,[33,252,57],{"emptyLinePlaceholder":56},[33,254,256],{"class":35,"line":255},22,[33,257,258],{"class":39},"# ── Process substitution runs in a subshell too ──\n",[33,260,262,265,268,271,274,276,278,281],{"class":35,"line":261},23,[33,263,264],{"class":46},"diff",[33,266,267],{"class":114}," \u003C(",[33,269,270],{"class":46},"sort",[33,272,273],{"class":114}," file1)",[33,275,267],{"class":114},[33,277,270],{"class":46},[33,279,280],{"class":114}," file2)",[33,282,283],{"class":39},"   # sort runs in subshells, output exposed as fds\n",[33,285,287],{"class":35,"line":286},24,[33,288,57],{"emptyLinePlaceholder":56},[33,290,292],{"class":35,"line":291},25,[33,293,294],{"class":39},"# ── Job control ──\n",[33,296,298,301,304],{"class":35,"line":297},26,[33,299,300],{"class":46},".\u002Fjob1.sh",[33,302,303],{"class":71}," &        ",[33,305,306],{"class":39},"# background job 1\n",[33,308,310,313,315],{"class":35,"line":309},27,[33,311,312],{"class":46},".\u002Fjob2.sh",[33,314,303],{"class":71},[33,316,317],{"class":39},"# background job 2\n",[33,319,321,324],{"class":35,"line":320},28,[33,322,323],{"class":110},"jobs",[33,325,326],{"class":39},"               # list all background jobs: [1]- Running  .\u002Fjob1.sh & [2]+ Running  .\u002Fjob2.sh &\n",[33,328,330,333,336],{"class":35,"line":329},29,[33,331,332],{"class":110},"fg",[33,334,335],{"class":114}," %1",[33,337,338],{"class":39},"              # bring job 1 to foreground (blocks until done or Ctrl-Z)\n",[33,340,342,345,347],{"class":35,"line":341},30,[33,343,344],{"class":110},"bg",[33,346,335],{"class":114},[33,348,349],{"class":39},"              # resume job 1 in background (if it was stopped with Ctrl-Z)\n",[33,351,353,356,358],{"class":35,"line":352},31,[33,354,355],{"class":110},"kill",[33,357,335],{"class":114},[33,359,360],{"class":39},"            # send SIGTERM to job 1\n",[33,362,364,366,369],{"class":35,"line":363},32,[33,365,355],{"class":110},[33,367,368],{"class":114}," %2",[33,370,371],{"class":39},"            # send SIGTERM to job 2\n",[33,373,375,378],{"class":35,"line":374},33,[33,376,377],{"class":110},"wait",[33,379,380],{"class":39},"               # wait for all background jobs to finish\n",[15,382,384,387,388,390],{"id":383},"and-wait-capturing-process-pids-and-exit-status",[30,385,386],{},"$!"," and ",[30,389,377],{},": Capturing Process PIDs and Exit Status",[20,392,393],{"language":22},[24,394,396],{"className":26,"code":395,"language":22,"meta":28,"style":28},"# ── $! is the PID of the last backgrounded command ──\n.\u002Fslow.sh &\npid=$!               # capture immediately — $! changes with each new background command\necho \"started PID $pid\"\n\n# ── wait for a specific PID, capture its exit status ──\nwait \"$pid\"\nstatus=$?\necho \"exit status: $status\"\n\n# ── Wait for all background jobs ──\n.\u002Fjob1.sh &\n.\u002Fjob2.sh &\n.\u002Fjob3.sh &\nwait                   # wait for ALL background jobs\n# ⚠️ $? after `wait` (no arg) is the exit status of the LAST job to finish (non-deterministic!)\n# To check each job individually, capture PIDs and wait for each:\n\n.\u002Fjob1.sh & pid1=$!\n.\u002Fjob2.sh & pid2=$!\n.\u002Fjob3.sh & pid3=$!\n\nwait \"$pid1\"; status1=$?\nwait \"$pid2\"; status2=$?\nwait \"$pid3\"; status3=$?\n\nif ((status1 == 0 && status2 == 0 && status3 == 0)); then\n    echo \"all succeeded\"\nelse\n    echo \"failed: j1=$status1 j2=$status2 j3=$status3\"\n    exit 1\nfi\n\n# ── wait -n: wait for ANY one job to finish (Bash 5.1+) ──\nfor i in 1 2 3 4 5; do\n    .\u002Fworker.sh \"$i\" &\ndone\nwait -n   # wait for any one to complete (returns its exit status)\necho \"one job finished with status $?\"\n# Useful for job pools: wait for a slot to free up before starting the next job.\n",[30,397,398,403,410,422,435,439,444,454,464,476,480,485,491,497,504,511,516,521,525,537,548,559,563,581,599,617,621,660,667,672,696,704,709,713,719,751,766,772,783,796],{"__ignoreMap":28},[33,399,400],{"class":35,"line":36},[33,401,402],{"class":39},"# ── $! is the PID of the last backgrounded command ──\n",[33,404,405,408],{"class":35,"line":43},[33,406,407],{"class":46},".\u002Fslow.sh",[33,409,72],{"class":71},[33,411,412,415,417,419],{"class":35,"line":53},[33,413,414],{"class":71},"pid",[33,416,179],{"class":178},[33,418,386],{"class":110},[33,420,421],{"class":39},"               # capture immediately — $! changes with each new background command\n",[33,423,424,426,429,432],{"class":35,"line":60},[33,425,148],{"class":110},[33,427,428],{"class":114}," \"started PID ",[33,430,431],{"class":71},"$pid",[33,433,434],{"class":114},"\"\n",[33,436,437],{"class":35,"line":66},[33,438,57],{"emptyLinePlaceholder":56},[33,440,441],{"class":35,"line":75},[33,442,443],{"class":39},"# ── wait for a specific PID, capture its exit status ──\n",[33,445,446,448,450,452],{"class":35,"line":81},[33,447,377],{"class":110},[33,449,206],{"class":114},[33,451,431],{"class":71},[33,453,434],{"class":114},[33,455,456,459,461],{"class":35,"line":87},[33,457,458],{"class":71},"status",[33,460,179],{"class":178},[33,462,463],{"class":110},"$?\n",[33,465,466,468,471,474],{"class":35,"line":92},[33,467,148],{"class":110},[33,469,470],{"class":114}," \"exit status: ",[33,472,473],{"class":71},"$status",[33,475,434],{"class":114},[33,477,478],{"class":35,"line":98},[33,479,57],{"emptyLinePlaceholder":56},[33,481,482],{"class":35,"line":107},[33,483,484],{"class":39},"# ── Wait for all background jobs ──\n",[33,486,487,489],{"class":35,"line":121},[33,488,300],{"class":46},[33,490,72],{"class":71},[33,492,493,495],{"class":35,"line":139},[33,494,312],{"class":46},[33,496,72],{"class":71},[33,498,499,502],{"class":35,"line":145},[33,500,501],{"class":46},".\u002Fjob3.sh",[33,503,72],{"class":71},[33,505,506,508],{"class":35,"line":161},[33,507,377],{"class":110},[33,509,510],{"class":39},"                   # wait for ALL background jobs\n",[33,512,513],{"class":35,"line":166},[33,514,515],{"class":39},"# ⚠️ $? after `wait` (no arg) is the exit status of the LAST job to finish (non-deterministic!)\n",[33,517,518],{"class":35,"line":172},[33,519,520],{"class":39},"# To check each job individually, capture PIDs and wait for each:\n",[33,522,523],{"class":35,"line":185},[33,524,57],{"emptyLinePlaceholder":56},[33,526,527,529,532,534],{"class":35,"line":221},[33,528,300],{"class":46},[33,530,531],{"class":71}," & pid1",[33,533,179],{"class":178},[33,535,536],{"class":110},"$!\n",[33,538,539,541,544,546],{"class":35,"line":236},[33,540,312],{"class":46},[33,542,543],{"class":71}," & pid2",[33,545,179],{"class":178},[33,547,536],{"class":110},[33,549,550,552,555,557],{"class":35,"line":250},[33,551,501],{"class":46},[33,553,554],{"class":71}," & pid3",[33,556,179],{"class":178},[33,558,536],{"class":110},[33,560,561],{"class":35,"line":255},[33,562,57],{"emptyLinePlaceholder":56},[33,564,565,567,569,572,574,577,579],{"class":35,"line":261},[33,566,377],{"class":110},[33,568,206],{"class":114},[33,570,571],{"class":71},"$pid1",[33,573,212],{"class":114},[33,575,576],{"class":71},"; status1",[33,578,179],{"class":178},[33,580,463],{"class":110},[33,582,583,585,587,590,592,595,597],{"class":35,"line":286},[33,584,377],{"class":110},[33,586,206],{"class":114},[33,588,589],{"class":71},"$pid2",[33,591,212],{"class":114},[33,593,594],{"class":71},"; status2",[33,596,179],{"class":178},[33,598,463],{"class":110},[33,600,601,603,605,608,610,613,615],{"class":35,"line":291},[33,602,377],{"class":110},[33,604,206],{"class":114},[33,606,607],{"class":71},"$pid3",[33,609,212],{"class":114},[33,611,612],{"class":71},"; status3",[33,614,179],{"class":178},[33,616,463],{"class":110},[33,618,619],{"class":35,"line":297},[33,620,57],{"emptyLinePlaceholder":56},[33,622,623,626,629,632,635,638,641,643,645,647,650,652,654,657],{"class":35,"line":309},[33,624,625],{"class":178},"if",[33,627,628],{"class":71}," ((status1 ",[33,630,631],{"class":178},"==",[33,633,634],{"class":110}," 0",[33,636,637],{"class":178}," &&",[33,639,640],{"class":71}," status2 ",[33,642,631],{"class":178},[33,644,634],{"class":110},[33,646,637],{"class":178},[33,648,649],{"class":71}," status3 ",[33,651,631],{"class":178},[33,653,634],{"class":110},[33,655,656],{"class":71},")); ",[33,658,659],{"class":178},"then\n",[33,661,662,664],{"class":35,"line":320},[33,663,124],{"class":110},[33,665,666],{"class":114}," \"all succeeded\"\n",[33,668,669],{"class":35,"line":329},[33,670,671],{"class":178},"else\n",[33,673,674,676,679,682,685,688,691,694],{"class":35,"line":341},[33,675,124],{"class":110},[33,677,678],{"class":114}," \"failed: j1=",[33,680,681],{"class":71},"$status1",[33,683,684],{"class":114}," j2=",[33,686,687],{"class":71},"$status2",[33,689,690],{"class":114}," j3=",[33,692,693],{"class":71},"$status3",[33,695,434],{"class":114},[33,697,698,701],{"class":35,"line":352},[33,699,700],{"class":110},"    exit",[33,702,703],{"class":110}," 1\n",[33,705,706],{"class":35,"line":363},[33,707,708],{"class":178},"fi\n",[33,710,711],{"class":35,"line":374},[33,712,57],{"emptyLinePlaceholder":56},[33,714,716],{"class":35,"line":715},34,[33,717,718],{"class":39},"# ── wait -n: wait for ANY one job to finish (Bash 5.1+) ──\n",[33,720,722,725,728,731,734,737,740,743,746,748],{"class":35,"line":721},35,[33,723,724],{"class":178},"for",[33,726,727],{"class":71}," i ",[33,729,730],{"class":178},"in",[33,732,733],{"class":114}," 1",[33,735,736],{"class":114}," 2",[33,738,739],{"class":114}," 3",[33,741,742],{"class":114}," 4",[33,744,745],{"class":114}," 5",[33,747,201],{"class":71},[33,749,750],{"class":178},"do\n",[33,752,754,757,759,762,764],{"class":35,"line":753},36,[33,755,756],{"class":46},"    .\u002Fworker.sh",[33,758,206],{"class":114},[33,760,761],{"class":71},"$i",[33,763,212],{"class":114},[33,765,72],{"class":71},[33,767,769],{"class":35,"line":768},37,[33,770,771],{"class":178},"done\n",[33,773,775,777,780],{"class":35,"line":774},38,[33,776,377],{"class":110},[33,778,779],{"class":110}," -n",[33,781,782],{"class":39},"   # wait for any one to complete (returns its exit status)\n",[33,784,786,788,791,794],{"class":35,"line":785},39,[33,787,148],{"class":110},[33,789,790],{"class":114}," \"one job finished with status ",[33,792,793],{"class":110},"$?",[33,795,434],{"class":114},[33,797,799],{"class":35,"line":798},40,[33,800,801],{"class":39},"# Useful for job pools: wait for a slot to free up before starting the next job.\n",[15,803,805,806,808],{"id":804},"anti-pattern-wait-without-pids","Anti-Pattern: ",[30,807,377],{}," Without PIDs",[20,810,811],{"language":22},[24,812,814],{"className":26,"code":813,"language":22,"meta":28,"style":28},"# ❌ NAIVE — $? after bare wait is non-deterministic (last job, not all jobs)\n.\u002Fjob1.sh &\n.\u002Fjob2.sh &\n.\u002Fjob3.sh &\nwait\nif [[ $? -eq 0 ]]; then\n    echo \"all succeeded\"   # WRONG — $? is only the last job's status, not all\nfi\n\n# ✅ CORRECT — capture PIDs, wait for each, check all\npids=()\n.\u002Fjob1.sh & pids+=($!)\n.\u002Fjob2.sh & pids+=($!)\n.\u002Fjob3.sh & pids+=($!)\n\nall_ok=true\nfor pid in \"${pids[@]}\"; do\n    wait \"$pid\" || all_ok=false   # if any fails, set flag\ndone\n$all_ok && echo \"all succeeded\" || echo \"some failed\"\n",[30,815,816,821,827,833,839,844,863,873,877,881,886,896,913,927,941,945,955,982,1007,1011],{"__ignoreMap":28},[33,817,818],{"class":35,"line":36},[33,819,820],{"class":39},"# ❌ NAIVE — $? after bare wait is non-deterministic (last job, not all jobs)\n",[33,822,823,825],{"class":35,"line":43},[33,824,300],{"class":46},[33,826,72],{"class":71},[33,828,829,831],{"class":35,"line":53},[33,830,312],{"class":46},[33,832,72],{"class":71},[33,834,835,837],{"class":35,"line":60},[33,836,501],{"class":46},[33,838,72],{"class":71},[33,840,841],{"class":35,"line":66},[33,842,843],{"class":110},"wait\n",[33,845,846,848,851,853,856,858,861],{"class":35,"line":75},[33,847,625],{"class":178},[33,849,850],{"class":71}," [[ ",[33,852,793],{"class":110},[33,854,855],{"class":178}," -eq",[33,857,634],{"class":110},[33,859,860],{"class":71}," ]]; ",[33,862,659],{"class":178},[33,864,865,867,870],{"class":35,"line":81},[33,866,124],{"class":110},[33,868,869],{"class":114}," \"all succeeded\"",[33,871,872],{"class":39},"   # WRONG — $? is only the last job's status, not all\n",[33,874,875],{"class":35,"line":87},[33,876,708],{"class":178},[33,878,879],{"class":35,"line":92},[33,880,57],{"emptyLinePlaceholder":56},[33,882,883],{"class":35,"line":98},[33,884,885],{"class":39},"# ✅ CORRECT — capture PIDs, wait for each, check all\n",[33,887,888,891,893],{"class":35,"line":107},[33,889,890],{"class":71},"pids",[33,892,179],{"class":178},[33,894,895],{"class":71},"()\n",[33,897,898,900,903,906,909,911],{"class":35,"line":121},[33,899,300],{"class":46},[33,901,902],{"class":71}," & pids",[33,904,905],{"class":178},"+=",[33,907,908],{"class":71},"(",[33,910,386],{"class":110},[33,912,142],{"class":71},[33,914,915,917,919,921,923,925],{"class":35,"line":139},[33,916,312],{"class":46},[33,918,902],{"class":71},[33,920,905],{"class":178},[33,922,908],{"class":71},[33,924,386],{"class":110},[33,926,142],{"class":71},[33,928,929,931,933,935,937,939],{"class":35,"line":145},[33,930,501],{"class":46},[33,932,902],{"class":71},[33,934,905],{"class":178},[33,936,908],{"class":71},[33,938,386],{"class":110},[33,940,142],{"class":71},[33,942,943],{"class":35,"line":161},[33,944,57],{"emptyLinePlaceholder":56},[33,946,947,950,952],{"class":35,"line":166},[33,948,949],{"class":71},"all_ok",[33,951,179],{"class":178},[33,953,954],{"class":114},"true\n",[33,956,957,959,962,964,967,969,972,975,978,980],{"class":35,"line":172},[33,958,724],{"class":178},[33,960,961],{"class":71}," pid ",[33,963,730],{"class":178},[33,965,966],{"class":114}," \"${",[33,968,890],{"class":71},[33,970,971],{"class":114},"[",[33,973,974],{"class":178},"@",[33,976,977],{"class":114},"]}\"",[33,979,201],{"class":71},[33,981,750],{"class":178},[33,983,984,987,989,991,993,996,999,1001,1004],{"class":35,"line":185},[33,985,986],{"class":110},"    wait",[33,988,206],{"class":114},[33,990,431],{"class":71},[33,992,212],{"class":114},[33,994,995],{"class":178}," ||",[33,997,998],{"class":71}," all_ok",[33,1000,179],{"class":178},[33,1002,1003],{"class":114},"false",[33,1005,1006],{"class":39},"   # if any fails, set flag\n",[33,1008,1009],{"class":35,"line":221},[33,1010,771],{"class":178},[33,1012,1013,1016,1018,1020,1022,1025],{"class":35,"line":236},[33,1014,1015],{"class":71},"$all_ok && ",[33,1017,148],{"class":110},[33,1019,869],{"class":114},[33,1021,995],{"class":178},[33,1023,1024],{"class":110}," echo",[33,1026,1027],{"class":114}," \"some failed\"\n",[15,1029,1031],{"id":1030},"signals-the-complete-dispatch-model","Signals: The Complete Dispatch Model",[20,1033,1034],{"language":22},[24,1035,1037],{"className":26,"code":1036,"language":22,"meta":28,"style":28},"# ── Common signals ──\n# Signal     Num  Default action    Can trap?  Meaning\n# SIGHUP     1    terminate         yes        terminal closed \u002F \"reload config\" convention\n# SIGINT     2    terminate         yes        Ctrl-C (interrupt)\n# SIGQUIT    3    core dump         yes        Ctrl-\\ (quit with core dump)\n# SIGKILL    9    terminate         NO         force kill (immediate, no cleanup — last resort)\n# SIGUSR1    10   terminate         yes        user-defined 1\n# SIGSEGV    11   core dump         yes        segfault (memory violation)\n# SIGUSR2    12   terminate         yes        user-defined 2\n# SIGTERM    15   terminate         yes        polite terminate (default for `kill`)\n# SIGSTOP    19   stop (pause)      NO         pause process (can't be caught)\n# SIGCONT    18   resume            yes        resume a stopped process\n# SIGTSTP    20   stop              yes        Ctrl-Z (terminal stop — can be caught)\n\n# ── Sending signals ──\nkill $pid            # SIGTERM (default) — polite, can be trapped for cleanup\nkill -TERM $pid      # same, explicit\nkill -15 $pid        # same, by number\nkill -9 $pid         # SIGKILL — can't be caught, immediate, no cleanup\nkill -HUP $pid       # SIGHUP — often \"reload config\"\nkill -INT $pid       # SIGINT — like Ctrl-C\nkill -USR1 $pid      # SIGUSR1 — custom trigger\nkill -l              # list all signals (with numbers)\nkill -0 $pid         # check if process exists (exit 0 = alive, exit 1 = dead)\n\n# ── Signal shortcuts ──\nkill -9 $pid         # SIGKILL — force, no cleanup. LAST RESORT.\nkill -TERM $pid      # SIGTERM — polite. Try this FIRST, then -9 after a timeout.\nkill -l SIGTERM      # 15 — get signal number from name\nkill -l 15           # TERM — get signal name from number\n",[30,1038,1039,1044,1049,1054,1059,1064,1069,1074,1079,1084,1089,1094,1099,1104,1108,1113,1123,1136,1149,1162,1175,1187,1199,1209,1221,1225,1230,1241,1252,1264],{"__ignoreMap":28},[33,1040,1041],{"class":35,"line":36},[33,1042,1043],{"class":39},"# ── Common signals ──\n",[33,1045,1046],{"class":35,"line":43},[33,1047,1048],{"class":39},"# Signal     Num  Default action    Can trap?  Meaning\n",[33,1050,1051],{"class":35,"line":53},[33,1052,1053],{"class":39},"# SIGHUP     1    terminate         yes        terminal closed \u002F \"reload config\" convention\n",[33,1055,1056],{"class":35,"line":60},[33,1057,1058],{"class":39},"# SIGINT     2    terminate         yes        Ctrl-C (interrupt)\n",[33,1060,1061],{"class":35,"line":66},[33,1062,1063],{"class":39},"# SIGQUIT    3    core dump         yes        Ctrl-\\ (quit with core dump)\n",[33,1065,1066],{"class":35,"line":75},[33,1067,1068],{"class":39},"# SIGKILL    9    terminate         NO         force kill (immediate, no cleanup — last resort)\n",[33,1070,1071],{"class":35,"line":81},[33,1072,1073],{"class":39},"# SIGUSR1    10   terminate         yes        user-defined 1\n",[33,1075,1076],{"class":35,"line":87},[33,1077,1078],{"class":39},"# SIGSEGV    11   core dump         yes        segfault (memory violation)\n",[33,1080,1081],{"class":35,"line":92},[33,1082,1083],{"class":39},"# SIGUSR2    12   terminate         yes        user-defined 2\n",[33,1085,1086],{"class":35,"line":98},[33,1087,1088],{"class":39},"# SIGTERM    15   terminate         yes        polite terminate (default for `kill`)\n",[33,1090,1091],{"class":35,"line":107},[33,1092,1093],{"class":39},"# SIGSTOP    19   stop (pause)      NO         pause process (can't be caught)\n",[33,1095,1096],{"class":35,"line":121},[33,1097,1098],{"class":39},"# SIGCONT    18   resume            yes        resume a stopped process\n",[33,1100,1101],{"class":35,"line":139},[33,1102,1103],{"class":39},"# SIGTSTP    20   stop              yes        Ctrl-Z (terminal stop — can be caught)\n",[33,1105,1106],{"class":35,"line":145},[33,1107,57],{"emptyLinePlaceholder":56},[33,1109,1110],{"class":35,"line":161},[33,1111,1112],{"class":39},"# ── Sending signals ──\n",[33,1114,1115,1117,1120],{"class":35,"line":166},[33,1116,355],{"class":110},[33,1118,1119],{"class":71}," $pid            ",[33,1121,1122],{"class":39},"# SIGTERM (default) — polite, can be trapped for cleanup\n",[33,1124,1125,1127,1130,1133],{"class":35,"line":172},[33,1126,355],{"class":110},[33,1128,1129],{"class":110}," -TERM",[33,1131,1132],{"class":71}," $pid      ",[33,1134,1135],{"class":39},"# same, explicit\n",[33,1137,1138,1140,1143,1146],{"class":35,"line":185},[33,1139,355],{"class":110},[33,1141,1142],{"class":110}," -15",[33,1144,1145],{"class":71}," $pid        ",[33,1147,1148],{"class":39},"# same, by number\n",[33,1150,1151,1153,1156,1159],{"class":35,"line":221},[33,1152,355],{"class":110},[33,1154,1155],{"class":110}," -9",[33,1157,1158],{"class":71}," $pid         ",[33,1160,1161],{"class":39},"# SIGKILL — can't be caught, immediate, no cleanup\n",[33,1163,1164,1166,1169,1172],{"class":35,"line":236},[33,1165,355],{"class":110},[33,1167,1168],{"class":110}," -HUP",[33,1170,1171],{"class":71}," $pid       ",[33,1173,1174],{"class":39},"# SIGHUP — often \"reload config\"\n",[33,1176,1177,1179,1182,1184],{"class":35,"line":250},[33,1178,355],{"class":110},[33,1180,1181],{"class":110}," -INT",[33,1183,1171],{"class":71},[33,1185,1186],{"class":39},"# SIGINT — like Ctrl-C\n",[33,1188,1189,1191,1194,1196],{"class":35,"line":255},[33,1190,355],{"class":110},[33,1192,1193],{"class":110}," -USR1",[33,1195,1132],{"class":71},[33,1197,1198],{"class":39},"# SIGUSR1 — custom trigger\n",[33,1200,1201,1203,1206],{"class":35,"line":261},[33,1202,355],{"class":110},[33,1204,1205],{"class":110}," -l",[33,1207,1208],{"class":39},"              # list all signals (with numbers)\n",[33,1210,1211,1213,1216,1218],{"class":35,"line":286},[33,1212,355],{"class":110},[33,1214,1215],{"class":110}," -0",[33,1217,1158],{"class":71},[33,1219,1220],{"class":39},"# check if process exists (exit 0 = alive, exit 1 = dead)\n",[33,1222,1223],{"class":35,"line":291},[33,1224,57],{"emptyLinePlaceholder":56},[33,1226,1227],{"class":35,"line":297},[33,1228,1229],{"class":39},"# ── Signal shortcuts ──\n",[33,1231,1232,1234,1236,1238],{"class":35,"line":309},[33,1233,355],{"class":110},[33,1235,1155],{"class":110},[33,1237,1158],{"class":71},[33,1239,1240],{"class":39},"# SIGKILL — force, no cleanup. LAST RESORT.\n",[33,1242,1243,1245,1247,1249],{"class":35,"line":320},[33,1244,355],{"class":110},[33,1246,1129],{"class":110},[33,1248,1132],{"class":71},[33,1250,1251],{"class":39},"# SIGTERM — polite. Try this FIRST, then -9 after a timeout.\n",[33,1253,1254,1256,1258,1261],{"class":35,"line":329},[33,1255,355],{"class":110},[33,1257,1205],{"class":110},[33,1259,1260],{"class":114}," SIGTERM",[33,1262,1263],{"class":39},"      # 15 — get signal number from name\n",[33,1265,1266,1268,1270,1273],{"class":35,"line":341},[33,1267,355],{"class":110},[33,1269,1205],{"class":110},[33,1271,1272],{"class":110}," 15",[33,1274,1275],{"class":39},"           # TERM — get signal name from number\n",[15,1277,1279,1282],{"id":1278},"trap-signal-handling-for-graceful-shutdown",[30,1280,1281],{},"trap",": Signal Handling for Graceful Shutdown",[20,1284,1285],{"language":22},[24,1286,1288],{"className":26,"code":1287,"language":22,"meta":28,"style":28},"# ── trap registers a handler for one or more signals ──\ncleanup() {\n    echo \"cleaning up...\" >&2\n    [[ -n \"$tmpfile\" ]] && rm -f \"$tmpfile\"\n    [[ -n \"$child_pid\" ]] && kill \"$child_pid\" 2>\u002Fdev\u002Fnull\n    wait \"$child_pid\" 2>\u002Fdev\u002Fnull\n    exit 0    # or exit $exit_code to preserve the original\n}\n\ntmpfile=$(mktemp)\nchild_pid=\"\"\ntrap cleanup EXIT INT TERM   # handle normal exit, Ctrl-C, and SIGTERM\n\n# ── Start a child process ──\n.\u002Fserver.sh &\nchild_pid=$!\n\n# ── Main loop ──\nwhile true; do\n    echo \"working...\"\n    sleep 1\ndone\n\n# ── When the script exits (normally, Ctrl-C, or kill) ──\n# EXIT: fires on any exit (normal, set -e abort, signals if no specific trap)\n# INT:  fires on Ctrl-C (user interrupt)\n# TERM: fires on `kill` (termination request)\n# The trap runs in the MAIN shell — so $tmpfile and $child_pid are in scope.\n\n# ── Ignoring a signal (critical section) ──\ntrap '' INT    # ignore Ctrl-C during critical work\n# ... critical section that shouldn't be interrupted ...\ntrap - INT    # restore default (Ctrl-C kills the script)\n\n# ── Reload on SIGHUP ──\nload_config() {\n    source \"$CONFIG_FILE\"\n    echo \"config reloaded at $(date -Iseconds)\"\n}\ntrap load_config HUP   # kill -HUP $pid reloads config\n\n# ── Multiple signals, one handler ──\ntrap 'echo \"signal received: $?\"' INT TERM HUP\n\n# ── ERR trap (fires on command failure with set -e) ──\nset -E   # -E makes ERR trap inherit into functions and subshells (essential!)\nerr_handler() {\n    local code=$?\n    echo \"FAILED: '$BASH_COMMAND' at line $LINENO (exit $code)\" >&2\n}\ntrap err_handler ERR\n# ERR fires when a command fails and set -e would exit.\n# BASH_COMMAND: the failing command (string).\n# LINENO: current line number.\n# $?: exit status (capture FIRST — any command overwrites it).\n",[30,1289,1290,1295,1303,1313,1343,1372,1386,1395,1400,1404,1419,1429,1448,1452,1457,1464,1472,1476,1481,1493,1500,1507,1511,1515,1520,1525,1530,1535,1540,1544,1549,1561,1566,1578,1582,1587,1594,1606,1622,1626,1639,1644,1650,1665,1670,1676,1688,1696,1709,1736,1741,1752,1758,1764,1770],{"__ignoreMap":28},[33,1291,1292],{"class":35,"line":36},[33,1293,1294],{"class":39},"# ── trap registers a handler for one or more signals ──\n",[33,1296,1297,1300],{"class":35,"line":43},[33,1298,1299],{"class":46},"cleanup",[33,1301,1302],{"class":71},"() {\n",[33,1304,1305,1307,1310],{"class":35,"line":53},[33,1306,124],{"class":110},[33,1308,1309],{"class":114}," \"cleaning up...\"",[33,1311,1312],{"class":178}," >&2\n",[33,1314,1315,1318,1321,1323,1326,1328,1331,1334,1337,1339,1341],{"class":35,"line":60},[33,1316,1317],{"class":71},"    [[ ",[33,1319,1320],{"class":178},"-n",[33,1322,206],{"class":114},[33,1324,1325],{"class":71},"$tmpfile",[33,1327,212],{"class":114},[33,1329,1330],{"class":71}," ]] && ",[33,1332,1333],{"class":46},"rm",[33,1335,1336],{"class":110}," -f",[33,1338,206],{"class":114},[33,1340,1325],{"class":71},[33,1342,434],{"class":114},[33,1344,1345,1347,1349,1351,1354,1356,1358,1360,1362,1364,1366,1369],{"class":35,"line":66},[33,1346,1317],{"class":71},[33,1348,1320],{"class":178},[33,1350,206],{"class":114},[33,1352,1353],{"class":71},"$child_pid",[33,1355,212],{"class":114},[33,1357,1330],{"class":71},[33,1359,355],{"class":110},[33,1361,206],{"class":114},[33,1363,1353],{"class":71},[33,1365,212],{"class":114},[33,1367,1368],{"class":178}," 2>",[33,1370,1371],{"class":114},"\u002Fdev\u002Fnull\n",[33,1373,1374,1376,1378,1380,1382,1384],{"class":35,"line":75},[33,1375,986],{"class":110},[33,1377,206],{"class":114},[33,1379,1353],{"class":71},[33,1381,212],{"class":114},[33,1383,1368],{"class":178},[33,1385,1371],{"class":114},[33,1387,1388,1390,1392],{"class":35,"line":81},[33,1389,700],{"class":110},[33,1391,634],{"class":110},[33,1393,1394],{"class":39},"    # or exit $exit_code to preserve the original\n",[33,1396,1397],{"class":35,"line":87},[33,1398,1399],{"class":71},"}\n",[33,1401,1402],{"class":35,"line":92},[33,1403,57],{"emptyLinePlaceholder":56},[33,1405,1406,1409,1411,1414,1417],{"class":35,"line":98},[33,1407,1408],{"class":71},"tmpfile",[33,1410,179],{"class":178},[33,1412,1413],{"class":71},"$(",[33,1415,1416],{"class":46},"mktemp",[33,1418,142],{"class":71},[33,1420,1421,1424,1426],{"class":35,"line":107},[33,1422,1423],{"class":71},"child_pid",[33,1425,179],{"class":178},[33,1427,1428],{"class":114},"\"\"\n",[33,1430,1431,1433,1436,1439,1442,1445],{"class":35,"line":121},[33,1432,1281],{"class":110},[33,1434,1435],{"class":114}," cleanup",[33,1437,1438],{"class":114}," EXIT",[33,1440,1441],{"class":114}," INT",[33,1443,1444],{"class":114}," TERM",[33,1446,1447],{"class":39},"   # handle normal exit, Ctrl-C, and SIGTERM\n",[33,1449,1450],{"class":35,"line":139},[33,1451,57],{"emptyLinePlaceholder":56},[33,1453,1454],{"class":35,"line":145},[33,1455,1456],{"class":39},"# ── Start a child process ──\n",[33,1458,1459,1462],{"class":35,"line":161},[33,1460,1461],{"class":46},".\u002Fserver.sh",[33,1463,72],{"class":71},[33,1465,1466,1468,1470],{"class":35,"line":166},[33,1467,1423],{"class":71},[33,1469,179],{"class":178},[33,1471,536],{"class":110},[33,1473,1474],{"class":35,"line":172},[33,1475,57],{"emptyLinePlaceholder":56},[33,1477,1478],{"class":35,"line":185},[33,1479,1480],{"class":39},"# ── Main loop ──\n",[33,1482,1483,1486,1489,1491],{"class":35,"line":221},[33,1484,1485],{"class":178},"while",[33,1487,1488],{"class":110}," true",[33,1490,201],{"class":71},[33,1492,750],{"class":178},[33,1494,1495,1497],{"class":35,"line":236},[33,1496,124],{"class":110},[33,1498,1499],{"class":114}," \"working...\"\n",[33,1501,1502,1505],{"class":35,"line":250},[33,1503,1504],{"class":46},"    sleep",[33,1506,703],{"class":110},[33,1508,1509],{"class":35,"line":255},[33,1510,771],{"class":178},[33,1512,1513],{"class":35,"line":261},[33,1514,57],{"emptyLinePlaceholder":56},[33,1516,1517],{"class":35,"line":286},[33,1518,1519],{"class":39},"# ── When the script exits (normally, Ctrl-C, or kill) ──\n",[33,1521,1522],{"class":35,"line":291},[33,1523,1524],{"class":39},"# EXIT: fires on any exit (normal, set -e abort, signals if no specific trap)\n",[33,1526,1527],{"class":35,"line":297},[33,1528,1529],{"class":39},"# INT:  fires on Ctrl-C (user interrupt)\n",[33,1531,1532],{"class":35,"line":309},[33,1533,1534],{"class":39},"# TERM: fires on `kill` (termination request)\n",[33,1536,1537],{"class":35,"line":320},[33,1538,1539],{"class":39},"# The trap runs in the MAIN shell — so $tmpfile and $child_pid are in scope.\n",[33,1541,1542],{"class":35,"line":329},[33,1543,57],{"emptyLinePlaceholder":56},[33,1545,1546],{"class":35,"line":341},[33,1547,1548],{"class":39},"# ── Ignoring a signal (critical section) ──\n",[33,1550,1551,1553,1556,1558],{"class":35,"line":352},[33,1552,1281],{"class":110},[33,1554,1555],{"class":114}," ''",[33,1557,1441],{"class":114},[33,1559,1560],{"class":39},"    # ignore Ctrl-C during critical work\n",[33,1562,1563],{"class":35,"line":363},[33,1564,1565],{"class":39},"# ... critical section that shouldn't be interrupted ...\n",[33,1567,1568,1570,1573,1575],{"class":35,"line":374},[33,1569,1281],{"class":110},[33,1571,1572],{"class":114}," -",[33,1574,1441],{"class":114},[33,1576,1577],{"class":39},"    # restore default (Ctrl-C kills the script)\n",[33,1579,1580],{"class":35,"line":715},[33,1581,57],{"emptyLinePlaceholder":56},[33,1583,1584],{"class":35,"line":721},[33,1585,1586],{"class":39},"# ── Reload on SIGHUP ──\n",[33,1588,1589,1592],{"class":35,"line":753},[33,1590,1591],{"class":46},"load_config",[33,1593,1302],{"class":71},[33,1595,1596,1599,1601,1604],{"class":35,"line":768},[33,1597,1598],{"class":110},"    source",[33,1600,206],{"class":114},[33,1602,1603],{"class":71},"$CONFIG_FILE",[33,1605,434],{"class":114},[33,1607,1608,1610,1613,1616,1619],{"class":35,"line":774},[33,1609,124],{"class":110},[33,1611,1612],{"class":114}," \"config reloaded at $(",[33,1614,1615],{"class":46},"date",[33,1617,1618],{"class":110}," -Iseconds",[33,1620,1621],{"class":114},")\"\n",[33,1623,1624],{"class":35,"line":785},[33,1625,1399],{"class":71},[33,1627,1628,1630,1633,1636],{"class":35,"line":798},[33,1629,1281],{"class":110},[33,1631,1632],{"class":114}," load_config",[33,1634,1635],{"class":114}," HUP",[33,1637,1638],{"class":39},"   # kill -HUP $pid reloads config\n",[33,1640,1642],{"class":35,"line":1641},41,[33,1643,57],{"emptyLinePlaceholder":56},[33,1645,1647],{"class":35,"line":1646},42,[33,1648,1649],{"class":39},"# ── Multiple signals, one handler ──\n",[33,1651,1653,1655,1658,1660,1662],{"class":35,"line":1652},43,[33,1654,1281],{"class":110},[33,1656,1657],{"class":114}," 'echo \"signal received: $?\"'",[33,1659,1441],{"class":114},[33,1661,1444],{"class":114},[33,1663,1664],{"class":114}," HUP\n",[33,1666,1668],{"class":35,"line":1667},44,[33,1669,57],{"emptyLinePlaceholder":56},[33,1671,1673],{"class":35,"line":1672},45,[33,1674,1675],{"class":39},"# ── ERR trap (fires on command failure with set -e) ──\n",[33,1677,1679,1682,1685],{"class":35,"line":1678},46,[33,1680,1681],{"class":110},"set",[33,1683,1684],{"class":110}," -E",[33,1686,1687],{"class":39},"   # -E makes ERR trap inherit into functions and subshells (essential!)\n",[33,1689,1691,1694],{"class":35,"line":1690},47,[33,1692,1693],{"class":46},"err_handler",[33,1695,1302],{"class":71},[33,1697,1699,1702,1705,1707],{"class":35,"line":1698},48,[33,1700,1701],{"class":178},"    local",[33,1703,1704],{"class":71}," code",[33,1706,179],{"class":178},[33,1708,463],{"class":110},[33,1710,1712,1714,1717,1720,1723,1726,1729,1732,1734],{"class":35,"line":1711},49,[33,1713,124],{"class":110},[33,1715,1716],{"class":114}," \"FAILED: '",[33,1718,1719],{"class":71},"$BASH_COMMAND",[33,1721,1722],{"class":114},"' at line ",[33,1724,1725],{"class":71},"$LINENO",[33,1727,1728],{"class":114}," (exit ",[33,1730,1731],{"class":71},"$code",[33,1733,133],{"class":114},[33,1735,1312],{"class":178},[33,1737,1739],{"class":35,"line":1738},50,[33,1740,1399],{"class":71},[33,1742,1744,1746,1749],{"class":35,"line":1743},51,[33,1745,1281],{"class":110},[33,1747,1748],{"class":114}," err_handler",[33,1750,1751],{"class":114}," ERR\n",[33,1753,1755],{"class":35,"line":1754},52,[33,1756,1757],{"class":39},"# ERR fires when a command fails and set -e would exit.\n",[33,1759,1761],{"class":35,"line":1760},53,[33,1762,1763],{"class":39},"# BASH_COMMAND: the failing command (string).\n",[33,1765,1767],{"class":35,"line":1766},54,[33,1768,1769],{"class":39},"# LINENO: current line number.\n",[33,1771,1773],{"class":35,"line":1772},55,[33,1774,1775],{"class":39},"# $?: exit status (capture FIRST — any command overwrites it).\n",[15,1777,1779],{"id":1778},"production-pattern-graceful-server-shutdown","Production Pattern: Graceful Server Shutdown",[20,1781,1782],{"language":22},[24,1783,1785],{"className":26,"code":1784,"language":22,"meta":28,"style":28},"#!\u002Fusr\u002Fbin\u002Fenv bash\nset -Eeuo pipefail\n\n# ── A wrapper that starts a server, forwards signals, and cleans up ──\n\nserver_pid=\"\"\nstart_server() {\n    .\u002Fserver --port \"$PORT\" &\n    server_pid=$!\n    log INFO \"server started (PID $server_pid) on port $PORT\"\n}\n\nshutdown() {\n    local exit_code=$?    # capture BEFORE any other command\n    log INFO \"shutting down...\"\n\n    if [[ -n \"$server_pid\" ]] && kill -0 \"$server_pid\" 2>\u002Fdev\u002Fnull; then\n        log INFO \"sending SIGTERM to server...\"\n        kill -TERM \"$server_pid\"     # polite: let the server clean up\n\n        # Wait up to 10 seconds for graceful shutdown\n        for i in {1..10}; do\n            kill -0 \"$server_pid\" 2>\u002Fdev\u002Fnull || break\n            sleep 1\n        done\n\n        # If still alive after 10s, force kill\n        if kill -0 \"$server_pid\" 2>\u002Fdev\u002Fnull; then\n            log WARN \"server didn't shut down in 10s, sending SIGKILL\"\n            kill -KILL \"$server_pid\"\n        fi\n        wait \"$server_pid\" 2>\u002Fdev\u002Fnull\n    fi\n\n    log INFO \"shutdown complete (exit $exit_code)\"\n    exit \"$exit_code\"\n}\n\ntrap shutdown EXIT INT TERM\n\nPORT=\"${1:-8080}\"\nstart_server\n\n# Wait for the server to exit (or signal to arrive)\nwait \"$server_pid\"\n",[30,1786,1787,1792,1802,1806,1811,1815,1824,1831,1848,1857,1878,1882,1886,1893,1907,1916,1920,1956,1966,1982,1986,1991,2010,2032,2039,2044,2048,2053,2077,2088,2101,2106,2121,2126,2130,2144,2154,2158,2162,2176,2180,2200,2205,2209,2214],{"__ignoreMap":28},[33,1788,1789],{"class":35,"line":36},[33,1790,1791],{"class":39},"#!\u002Fusr\u002Fbin\u002Fenv bash\n",[33,1793,1794,1796,1799],{"class":35,"line":43},[33,1795,1681],{"class":110},[33,1797,1798],{"class":110}," -Eeuo",[33,1800,1801],{"class":114}," pipefail\n",[33,1803,1804],{"class":35,"line":53},[33,1805,57],{"emptyLinePlaceholder":56},[33,1807,1808],{"class":35,"line":60},[33,1809,1810],{"class":39},"# ── A wrapper that starts a server, forwards signals, and cleans up ──\n",[33,1812,1813],{"class":35,"line":66},[33,1814,57],{"emptyLinePlaceholder":56},[33,1816,1817,1820,1822],{"class":35,"line":75},[33,1818,1819],{"class":71},"server_pid",[33,1821,179],{"class":178},[33,1823,1428],{"class":114},[33,1825,1826,1829],{"class":35,"line":81},[33,1827,1828],{"class":46},"start_server",[33,1830,1302],{"class":71},[33,1832,1833,1836,1839,1841,1844,1846],{"class":35,"line":87},[33,1834,1835],{"class":46},"    .\u002Fserver",[33,1837,1838],{"class":110}," --port",[33,1840,206],{"class":114},[33,1842,1843],{"class":71},"$PORT",[33,1845,212],{"class":114},[33,1847,72],{"class":71},[33,1849,1850,1853,1855],{"class":35,"line":92},[33,1851,1852],{"class":71},"    server_pid",[33,1854,179],{"class":178},[33,1856,536],{"class":110},[33,1858,1859,1862,1865,1868,1871,1874,1876],{"class":35,"line":98},[33,1860,1861],{"class":46},"    log",[33,1863,1864],{"class":114}," INFO",[33,1866,1867],{"class":114}," \"server started (PID ",[33,1869,1870],{"class":71},"$server_pid",[33,1872,1873],{"class":114},") on port ",[33,1875,1843],{"class":71},[33,1877,434],{"class":114},[33,1879,1880],{"class":35,"line":107},[33,1881,1399],{"class":71},[33,1883,1884],{"class":35,"line":121},[33,1885,57],{"emptyLinePlaceholder":56},[33,1887,1888,1891],{"class":35,"line":139},[33,1889,1890],{"class":46},"shutdown",[33,1892,1302],{"class":71},[33,1894,1895,1897,1900,1902,1904],{"class":35,"line":145},[33,1896,1701],{"class":178},[33,1898,1899],{"class":71}," exit_code",[33,1901,179],{"class":178},[33,1903,793],{"class":110},[33,1905,1906],{"class":39},"    # capture BEFORE any other command\n",[33,1908,1909,1911,1913],{"class":35,"line":161},[33,1910,1861],{"class":46},[33,1912,1864],{"class":114},[33,1914,1915],{"class":114}," \"shutting down...\"\n",[33,1917,1918],{"class":35,"line":166},[33,1919,57],{"emptyLinePlaceholder":56},[33,1921,1922,1925,1927,1929,1931,1933,1935,1937,1939,1941,1943,1945,1947,1949,1952,1954],{"class":35,"line":172},[33,1923,1924],{"class":178},"    if",[33,1926,850],{"class":71},[33,1928,1320],{"class":178},[33,1930,206],{"class":114},[33,1932,1870],{"class":71},[33,1934,212],{"class":114},[33,1936,1330],{"class":71},[33,1938,355],{"class":110},[33,1940,1215],{"class":110},[33,1942,206],{"class":114},[33,1944,1870],{"class":71},[33,1946,212],{"class":114},[33,1948,1368],{"class":178},[33,1950,1951],{"class":114},"\u002Fdev\u002Fnull",[33,1953,201],{"class":71},[33,1955,659],{"class":178},[33,1957,1958,1961,1963],{"class":35,"line":185},[33,1959,1960],{"class":46},"        log",[33,1962,1864],{"class":114},[33,1964,1965],{"class":114}," \"sending SIGTERM to server...\"\n",[33,1967,1968,1971,1973,1975,1977,1979],{"class":35,"line":221},[33,1969,1970],{"class":110},"        kill",[33,1972,1129],{"class":110},[33,1974,206],{"class":114},[33,1976,1870],{"class":71},[33,1978,212],{"class":114},[33,1980,1981],{"class":39},"     # polite: let the server clean up\n",[33,1983,1984],{"class":35,"line":236},[33,1985,57],{"emptyLinePlaceholder":56},[33,1987,1988],{"class":35,"line":250},[33,1989,1990],{"class":39},"        # Wait up to 10 seconds for graceful shutdown\n",[33,1992,1993,1996,1998,2000,2003,2006,2008],{"class":35,"line":255},[33,1994,1995],{"class":178},"        for",[33,1997,727],{"class":71},[33,1999,730],{"class":178},[33,2001,2002],{"class":71}," {",[33,2004,2005],{"class":46},"1..10}",[33,2007,201],{"class":71},[33,2009,750],{"class":178},[33,2011,2012,2015,2017,2019,2021,2023,2025,2027,2029],{"class":35,"line":261},[33,2013,2014],{"class":110},"            kill",[33,2016,1215],{"class":110},[33,2018,206],{"class":114},[33,2020,1870],{"class":71},[33,2022,212],{"class":114},[33,2024,1368],{"class":178},[33,2026,1951],{"class":114},[33,2028,995],{"class":178},[33,2030,2031],{"class":178}," break\n",[33,2033,2034,2037],{"class":35,"line":286},[33,2035,2036],{"class":46},"            sleep",[33,2038,703],{"class":110},[33,2040,2041],{"class":35,"line":291},[33,2042,2043],{"class":178},"        done\n",[33,2045,2046],{"class":35,"line":297},[33,2047,57],{"emptyLinePlaceholder":56},[33,2049,2050],{"class":35,"line":309},[33,2051,2052],{"class":39},"        # If still alive after 10s, force kill\n",[33,2054,2055,2058,2061,2063,2065,2067,2069,2071,2073,2075],{"class":35,"line":320},[33,2056,2057],{"class":178},"        if",[33,2059,2060],{"class":110}," kill",[33,2062,1215],{"class":110},[33,2064,206],{"class":114},[33,2066,1870],{"class":71},[33,2068,212],{"class":114},[33,2070,1368],{"class":178},[33,2072,1951],{"class":114},[33,2074,201],{"class":71},[33,2076,659],{"class":178},[33,2078,2079,2082,2085],{"class":35,"line":329},[33,2080,2081],{"class":46},"            log",[33,2083,2084],{"class":114}," WARN",[33,2086,2087],{"class":114}," \"server didn't shut down in 10s, sending SIGKILL\"\n",[33,2089,2090,2092,2095,2097,2099],{"class":35,"line":341},[33,2091,2014],{"class":110},[33,2093,2094],{"class":110}," -KILL",[33,2096,206],{"class":114},[33,2098,1870],{"class":71},[33,2100,434],{"class":114},[33,2102,2103],{"class":35,"line":352},[33,2104,2105],{"class":178},"        fi\n",[33,2107,2108,2111,2113,2115,2117,2119],{"class":35,"line":363},[33,2109,2110],{"class":110},"        wait",[33,2112,206],{"class":114},[33,2114,1870],{"class":71},[33,2116,212],{"class":114},[33,2118,1368],{"class":178},[33,2120,1371],{"class":114},[33,2122,2123],{"class":35,"line":374},[33,2124,2125],{"class":178},"    fi\n",[33,2127,2128],{"class":35,"line":715},[33,2129,57],{"emptyLinePlaceholder":56},[33,2131,2132,2134,2136,2139,2142],{"class":35,"line":721},[33,2133,1861],{"class":46},[33,2135,1864],{"class":114},[33,2137,2138],{"class":114}," \"shutdown complete (exit ",[33,2140,2141],{"class":71},"$exit_code",[33,2143,1621],{"class":114},[33,2145,2146,2148,2150,2152],{"class":35,"line":753},[33,2147,700],{"class":110},[33,2149,206],{"class":114},[33,2151,2141],{"class":71},[33,2153,434],{"class":114},[33,2155,2156],{"class":35,"line":768},[33,2157,1399],{"class":71},[33,2159,2160],{"class":35,"line":774},[33,2161,57],{"emptyLinePlaceholder":56},[33,2163,2164,2166,2169,2171,2173],{"class":35,"line":785},[33,2165,1281],{"class":110},[33,2167,2168],{"class":114}," shutdown",[33,2170,1438],{"class":114},[33,2172,1441],{"class":114},[33,2174,2175],{"class":114}," TERM\n",[33,2177,2178],{"class":35,"line":798},[33,2179,57],{"emptyLinePlaceholder":56},[33,2181,2182,2185,2187,2189,2192,2195,2198],{"class":35,"line":1641},[33,2183,2184],{"class":71},"PORT",[33,2186,179],{"class":178},[33,2188,212],{"class":114},[33,2190,2191],{"class":110},"${1",[33,2193,2194],{"class":178},":-",[33,2196,2197],{"class":110},"8080}",[33,2199,434],{"class":114},[33,2201,2202],{"class":35,"line":1646},[33,2203,2204],{"class":46},"start_server\n",[33,2206,2207],{"class":35,"line":1652},[33,2208,57],{"emptyLinePlaceholder":56},[33,2210,2211],{"class":35,"line":1667},[33,2212,2213],{"class":39},"# Wait for the server to exit (or signal to arrive)\n",[33,2215,2216,2218,2220,2222],{"class":35,"line":1672},[33,2217,377],{"class":110},[33,2219,206],{"class":114},[33,2221,1870],{"class":71},[33,2223,434],{"class":114},[15,2225,2227,2230],{"id":2226},"xargs-parallel-processing",[30,2228,2229],{},"xargs",": Parallel Processing",[20,2232,2233],{"language":22},[24,2234,2236],{"className":26,"code":2235,"language":22,"meta":28,"style":28},"# ── xargs reads stdin and passes items as args to a command ──\n# Without -0: splits on whitespace (breaks on spaces — dangerous for filenames)\n# With -0: splits on null bytes (safe with find -print0)\n\n# ── Basic usage ──\necho \"file1 file2 file3\" | xargs rm                 # rm file1 file2 file3\nfind . -name \"*.log\" | xargs grep \"error\"           # grep \"error\" in all .log files\nfind . -name \"*.log\" -print0 | xargs -0 grep \"error\"  # safe (null-delimited)\n\n# ── -P N: run N processes in parallel ──\nfind . -name \"*.png\" -print0 | xargs -0 -P4 -I{} convert {} {}.thumb.png\n# -P4: 4 processes in parallel\n# -I{}: use {} as placeholder for each filename\n# -0: null-delimited (safe with -print0)\n\n# ── -n N: pass N args per command invocation ──\necho \"a b c d e f\" | xargs -n2 echo\n# a b\n# c d\n# e f\n\n# ── -I{}: custom placeholder ──\nfind . -name \"*.py\" -print0 | xargs -0 -I{} python -m py_compile {}\n# {} is replaced with each filename (one at a time with -I)\n\n# ── Running a function with xargs (requires export -f) ──\nprocess_file() {\n    local f=$1\n    echo \"processing $f\"\n    # ... real work ...\n}\nexport -f process_file\n\nfind . -name \"*.txt\" -print0 | xargs -0 -P4 -I{} bash -c 'process_file \"$1\"' _ {}\n# _ is $0 (shell name, unused), {} becomes $1\n# export -f is required because xargs runs bash -c in a CHILD PROCESS\n\n# ── Parallel with max args per process ──\nfind . -name \"*.py\" -print0 | xargs -0 -P4 -n10 py_compile\n# -P4: 4 parallel processes, -n10: 10 files per process (40 files in flight)\n",[30,2237,2238,2243,2248,2253,2257,2262,2281,2308,2334,2338,2343,2371,2376,2381,2386,2390,2395,2412,2417,2422,2427,2431,2436,2460,2465,2469,2474,2481,2494,2506,2511,2515,2525,2529,2555,2560,2565,2569,2574,2600],{"__ignoreMap":28},[33,2239,2240],{"class":35,"line":36},[33,2241,2242],{"class":39},"# ── xargs reads stdin and passes items as args to a command ──\n",[33,2244,2245],{"class":35,"line":43},[33,2246,2247],{"class":39},"# Without -0: splits on whitespace (breaks on spaces — dangerous for filenames)\n",[33,2249,2250],{"class":35,"line":53},[33,2251,2252],{"class":39},"# With -0: splits on null bytes (safe with find -print0)\n",[33,2254,2255],{"class":35,"line":60},[33,2256,57],{"emptyLinePlaceholder":56},[33,2258,2259],{"class":35,"line":66},[33,2260,2261],{"class":39},"# ── Basic usage ──\n",[33,2263,2264,2266,2269,2272,2275,2278],{"class":35,"line":75},[33,2265,148],{"class":110},[33,2267,2268],{"class":114}," \"file1 file2 file3\"",[33,2270,2271],{"class":178}," |",[33,2273,2274],{"class":46}," xargs",[33,2276,2277],{"class":114}," rm",[33,2279,2280],{"class":39},"                 # rm file1 file2 file3\n",[33,2282,2283,2286,2289,2292,2295,2297,2299,2302,2305],{"class":35,"line":81},[33,2284,2285],{"class":46},"find",[33,2287,2288],{"class":114}," .",[33,2290,2291],{"class":110}," -name",[33,2293,2294],{"class":114}," \"*.log\"",[33,2296,2271],{"class":178},[33,2298,2274],{"class":46},[33,2300,2301],{"class":114}," grep",[33,2303,2304],{"class":114}," \"error\"",[33,2306,2307],{"class":39},"           # grep \"error\" in all .log files\n",[33,2309,2310,2312,2314,2316,2318,2321,2323,2325,2327,2329,2331],{"class":35,"line":87},[33,2311,2285],{"class":46},[33,2313,2288],{"class":114},[33,2315,2291],{"class":110},[33,2317,2294],{"class":114},[33,2319,2320],{"class":110}," -print0",[33,2322,2271],{"class":178},[33,2324,2274],{"class":46},[33,2326,1215],{"class":110},[33,2328,2301],{"class":114},[33,2330,2304],{"class":114},[33,2332,2333],{"class":39},"  # safe (null-delimited)\n",[33,2335,2336],{"class":35,"line":92},[33,2337,57],{"emptyLinePlaceholder":56},[33,2339,2340],{"class":35,"line":98},[33,2341,2342],{"class":39},"# ── -P N: run N processes in parallel ──\n",[33,2344,2345,2347,2349,2351,2354,2356,2358,2360,2362,2365,2368],{"class":35,"line":107},[33,2346,2285],{"class":46},[33,2348,2288],{"class":114},[33,2350,2291],{"class":110},[33,2352,2353],{"class":114}," \"*.png\"",[33,2355,2320],{"class":110},[33,2357,2271],{"class":178},[33,2359,2274],{"class":46},[33,2361,1215],{"class":110},[33,2363,2364],{"class":110}," -P4",[33,2366,2367],{"class":110}," -I",[33,2369,2370],{"class":71},"{} convert {} {}.thumb.png\n",[33,2372,2373],{"class":35,"line":121},[33,2374,2375],{"class":39},"# -P4: 4 processes in parallel\n",[33,2377,2378],{"class":35,"line":139},[33,2379,2380],{"class":39},"# -I{}: use {} as placeholder for each filename\n",[33,2382,2383],{"class":35,"line":145},[33,2384,2385],{"class":39},"# -0: null-delimited (safe with -print0)\n",[33,2387,2388],{"class":35,"line":161},[33,2389,57],{"emptyLinePlaceholder":56},[33,2391,2392],{"class":35,"line":166},[33,2393,2394],{"class":39},"# ── -n N: pass N args per command invocation ──\n",[33,2396,2397,2399,2402,2404,2406,2409],{"class":35,"line":172},[33,2398,148],{"class":110},[33,2400,2401],{"class":114}," \"a b c d e f\"",[33,2403,2271],{"class":178},[33,2405,2274],{"class":46},[33,2407,2408],{"class":110}," -n2",[33,2410,2411],{"class":114}," echo\n",[33,2413,2414],{"class":35,"line":185},[33,2415,2416],{"class":39},"# a b\n",[33,2418,2419],{"class":35,"line":221},[33,2420,2421],{"class":39},"# c d\n",[33,2423,2424],{"class":35,"line":236},[33,2425,2426],{"class":39},"# e f\n",[33,2428,2429],{"class":35,"line":250},[33,2430,57],{"emptyLinePlaceholder":56},[33,2432,2433],{"class":35,"line":255},[33,2434,2435],{"class":39},"# ── -I{}: custom placeholder ──\n",[33,2437,2438,2440,2442,2444,2447,2449,2451,2453,2455,2457],{"class":35,"line":261},[33,2439,2285],{"class":46},[33,2441,2288],{"class":114},[33,2443,2291],{"class":110},[33,2445,2446],{"class":114}," \"*.py\"",[33,2448,2320],{"class":110},[33,2450,2271],{"class":178},[33,2452,2274],{"class":46},[33,2454,1215],{"class":110},[33,2456,2367],{"class":110},[33,2458,2459],{"class":71},"{} python -m py_compile {}\n",[33,2461,2462],{"class":35,"line":286},[33,2463,2464],{"class":39},"# {} is replaced with each filename (one at a time with -I)\n",[33,2466,2467],{"class":35,"line":291},[33,2468,57],{"emptyLinePlaceholder":56},[33,2470,2471],{"class":35,"line":297},[33,2472,2473],{"class":39},"# ── Running a function with xargs (requires export -f) ──\n",[33,2475,2476,2479],{"class":35,"line":309},[33,2477,2478],{"class":46},"process_file",[33,2480,1302],{"class":71},[33,2482,2483,2485,2488,2490],{"class":35,"line":320},[33,2484,1701],{"class":178},[33,2486,2487],{"class":71}," f",[33,2489,179],{"class":178},[33,2491,2493],{"class":2492},"sCrzJ","$1\n",[33,2495,2496,2498,2501,2504],{"class":35,"line":329},[33,2497,124],{"class":110},[33,2499,2500],{"class":114}," \"processing ",[33,2502,2503],{"class":71},"$f",[33,2505,434],{"class":114},[33,2507,2508],{"class":35,"line":341},[33,2509,2510],{"class":39},"    # ... real work ...\n",[33,2512,2513],{"class":35,"line":352},[33,2514,1399],{"class":71},[33,2516,2517,2520,2522],{"class":35,"line":363},[33,2518,2519],{"class":178},"export",[33,2521,1336],{"class":110},[33,2523,2524],{"class":71}," process_file\n",[33,2526,2527],{"class":35,"line":374},[33,2528,57],{"emptyLinePlaceholder":56},[33,2530,2531,2533,2535,2537,2540,2542,2544,2546,2548,2550,2552],{"class":35,"line":715},[33,2532,2285],{"class":46},[33,2534,2288],{"class":114},[33,2536,2291],{"class":110},[33,2538,2539],{"class":114}," \"*.txt\"",[33,2541,2320],{"class":110},[33,2543,2271],{"class":178},[33,2545,2274],{"class":46},[33,2547,1215],{"class":110},[33,2549,2364],{"class":110},[33,2551,2367],{"class":110},[33,2553,2554],{"class":71},"{} bash -c 'process_file \"$1\"' _ {}\n",[33,2556,2557],{"class":35,"line":721},[33,2558,2559],{"class":39},"# _ is $0 (shell name, unused), {} becomes $1\n",[33,2561,2562],{"class":35,"line":753},[33,2563,2564],{"class":39},"# export -f is required because xargs runs bash -c in a CHILD PROCESS\n",[33,2566,2567],{"class":35,"line":768},[33,2568,57],{"emptyLinePlaceholder":56},[33,2570,2571],{"class":35,"line":774},[33,2572,2573],{"class":39},"# ── Parallel with max args per process ──\n",[33,2575,2576,2578,2580,2582,2584,2586,2588,2590,2592,2594,2597],{"class":35,"line":785},[33,2577,2285],{"class":46},[33,2579,2288],{"class":114},[33,2581,2291],{"class":110},[33,2583,2446],{"class":114},[33,2585,2320],{"class":110},[33,2587,2271],{"class":178},[33,2589,2274],{"class":46},[33,2591,1215],{"class":110},[33,2593,2364],{"class":110},[33,2595,2596],{"class":110}," -n10",[33,2598,2599],{"class":114}," py_compile\n",[33,2601,2602],{"class":35,"line":798},[33,2603,2604],{"class":39},"# -P4: 4 parallel processes, -n10: 10 files per process (40 files in flight)\n",[15,2606,2608],{"id":2607},"anti-pattern-parallel-jobs-without-error-handling","Anti-Pattern: Parallel Jobs Without Error Handling",[20,2610,2611],{"language":22},[24,2612,2614],{"className":26,"code":2613,"language":22,"meta":28,"style":28},"# ❌ NAIVE — no error checking, no output capture\nfor url in \"${urls[@]}\"; do\n    curl -s \"$url\" &  # fire and forget\ndone\nwait  # wait for all — but no exit status checking!\n\n# ✅ CORRECT — capture PIDs, check each, collect failures\ndeclare -a pids=()\nfor url in \"${urls[@]}\"; do\n    curl -s \"$url\" -o \"\u002Ftmp\u002Fresult_$RANDOM\" &\n    pids+=($!)\ndone\n\nfailures=0\nfor pid in \"${pids[@]}\"; do\n    wait \"$pid\" || ((failures++))\ndone\nif ((failures > 0)); then\n    echo \"failed: $failures\u002F${#pids[@]}\" >&2\n    exit 1\nfi\n",[30,2615,2616,2621,2645,2666,2670,2677,2681,2686,2701,2723,2748,2761,2765,2769,2779,2801,2822,2826,2842,2868,2874],{"__ignoreMap":28},[33,2617,2618],{"class":35,"line":36},[33,2619,2620],{"class":39},"# ❌ NAIVE — no error checking, no output capture\n",[33,2622,2623,2625,2628,2630,2632,2635,2637,2639,2641,2643],{"class":35,"line":43},[33,2624,724],{"class":178},[33,2626,2627],{"class":71}," url ",[33,2629,730],{"class":178},[33,2631,966],{"class":114},[33,2633,2634],{"class":71},"urls",[33,2636,971],{"class":114},[33,2638,974],{"class":178},[33,2640,977],{"class":114},[33,2642,201],{"class":71},[33,2644,750],{"class":178},[33,2646,2647,2650,2653,2655,2658,2660,2663],{"class":35,"line":53},[33,2648,2649],{"class":46},"    curl",[33,2651,2652],{"class":110}," -s",[33,2654,206],{"class":114},[33,2656,2657],{"class":71},"$url",[33,2659,212],{"class":114},[33,2661,2662],{"class":71}," &  ",[33,2664,2665],{"class":39},"# fire and forget\n",[33,2667,2668],{"class":35,"line":60},[33,2669,771],{"class":178},[33,2671,2672,2674],{"class":35,"line":66},[33,2673,377],{"class":110},[33,2675,2676],{"class":39},"  # wait for all — but no exit status checking!\n",[33,2678,2679],{"class":35,"line":75},[33,2680,57],{"emptyLinePlaceholder":56},[33,2682,2683],{"class":35,"line":81},[33,2684,2685],{"class":39},"# ✅ CORRECT — capture PIDs, check each, collect failures\n",[33,2687,2688,2691,2694,2697,2699],{"class":35,"line":87},[33,2689,2690],{"class":178},"declare",[33,2692,2693],{"class":110}," -a",[33,2695,2696],{"class":71}," pids",[33,2698,179],{"class":178},[33,2700,895],{"class":71},[33,2702,2703,2705,2707,2709,2711,2713,2715,2717,2719,2721],{"class":35,"line":92},[33,2704,724],{"class":178},[33,2706,2627],{"class":71},[33,2708,730],{"class":178},[33,2710,966],{"class":114},[33,2712,2634],{"class":71},[33,2714,971],{"class":114},[33,2716,974],{"class":178},[33,2718,977],{"class":114},[33,2720,201],{"class":71},[33,2722,750],{"class":178},[33,2724,2725,2727,2729,2731,2733,2735,2738,2741,2744,2746],{"class":35,"line":98},[33,2726,2649],{"class":46},[33,2728,2652],{"class":110},[33,2730,206],{"class":114},[33,2732,2657],{"class":71},[33,2734,212],{"class":114},[33,2736,2737],{"class":110}," -o",[33,2739,2740],{"class":114}," \"\u002Ftmp\u002Fresult_",[33,2742,2743],{"class":71},"$RANDOM",[33,2745,212],{"class":114},[33,2747,72],{"class":71},[33,2749,2750,2753,2755,2757,2759],{"class":35,"line":107},[33,2751,2752],{"class":71},"    pids",[33,2754,905],{"class":178},[33,2756,908],{"class":71},[33,2758,386],{"class":110},[33,2760,142],{"class":71},[33,2762,2763],{"class":35,"line":121},[33,2764,771],{"class":178},[33,2766,2767],{"class":35,"line":139},[33,2768,57],{"emptyLinePlaceholder":56},[33,2770,2771,2774,2776],{"class":35,"line":145},[33,2772,2773],{"class":71},"failures",[33,2775,179],{"class":178},[33,2777,2778],{"class":114},"0\n",[33,2780,2781,2783,2785,2787,2789,2791,2793,2795,2797,2799],{"class":35,"line":161},[33,2782,724],{"class":178},[33,2784,961],{"class":71},[33,2786,730],{"class":178},[33,2788,966],{"class":114},[33,2790,890],{"class":71},[33,2792,971],{"class":114},[33,2794,974],{"class":178},[33,2796,977],{"class":114},[33,2798,201],{"class":71},[33,2800,750],{"class":178},[33,2802,2803,2805,2807,2809,2811,2813,2816,2819],{"class":35,"line":166},[33,2804,986],{"class":110},[33,2806,206],{"class":114},[33,2808,431],{"class":71},[33,2810,212],{"class":114},[33,2812,995],{"class":178},[33,2814,2815],{"class":71}," ((failures",[33,2817,2818],{"class":178},"++",[33,2820,2821],{"class":71},"))\n",[33,2823,2824],{"class":35,"line":172},[33,2825,771],{"class":178},[33,2827,2828,2830,2833,2836,2838,2840],{"class":35,"line":185},[33,2829,625],{"class":178},[33,2831,2832],{"class":71}," ((failures ",[33,2834,2835],{"class":178},">",[33,2837,634],{"class":110},[33,2839,656],{"class":71},[33,2841,659],{"class":178},[33,2843,2844,2846,2849,2852,2855,2858,2860,2862,2864,2866],{"class":35,"line":221},[33,2845,124],{"class":110},[33,2847,2848],{"class":114}," \"failed: ",[33,2850,2851],{"class":71},"$failures",[33,2853,2854],{"class":114},"\u002F${",[33,2856,2857],{"class":178},"#",[33,2859,890],{"class":71},[33,2861,971],{"class":114},[33,2863,974],{"class":178},[33,2865,977],{"class":114},[33,2867,1312],{"class":178},[33,2869,2870,2872],{"class":35,"line":236},[33,2871,700],{"class":110},[33,2873,703],{"class":110},[33,2875,2876],{"class":35,"line":250},[33,2877,708],{"class":178},[15,2879,2881,2884],{"id":2880},"timeout-enforcing-time-limits",[30,2882,2883],{},"timeout",": Enforcing Time Limits",[20,2886,2887],{"language":22},[24,2888,2890],{"className":26,"code":2889,"language":22,"meta":28,"style":28},"# ── timeout runs a command with a time limit ──\ntimeout 30 .\u002Fslow_script.sh        # kill after 30s (SIGTERM)\ntimeout -s KILL 30 .\u002Fslow.sh       # use SIGKILL after 30s\ntimeout -k 5 30 .\u002Fslow.sh          # SIGTERM after 30s, then SIGKILL after 5 more if still running\ntimeout --preserve-status 30 .\u002Fscript.sh  # preserve the command's exit status (not 124)\n\n# ── Exit codes ──\n# timeout returns 124 if the command timed out, or the command's own exit status otherwise.\n# Distinguish:\ntimeout 30 .\u002Fslow.sh\nstatus=$?\nif ((status == 124)); then\n    echo \"timed out\"\nelif ((status == 137)); then\n    echo \"killed (SIGKILL after timeout + grace period)\"\nelse\n    echo \"exit: $status\"\nfi\n\n# ── Timeout with retry ──\nretry_with_timeout() {\n    local max=$1 t=$2; shift 2\n    local attempt=1\n    while ((attempt \u003C= max)); do\n        timeout \"$t\" \"$@\" && return 0\n        local code=$?\n        ((code == 124)) && echo \"attempt $attempt: timed out\" >&2\n        ((code != 124)) && echo \"attempt $attempt: exit $code\" >&2\n        ((attempt++))\n        sleep 2\n    done\n    return 1\n}\nretry_with_timeout 3 30 curl -s \"$url\"\n",[30,2891,2892,2897,2910,2927,2943,2958,2962,2967,2972,2977,2986,2994,3010,3017,3033,3040,3044,3055,3059,3063,3068,3075,3103,3115,3131,3159,3170,3195,3221,3230,3237,3242,3249,3253],{"__ignoreMap":28},[33,2893,2894],{"class":35,"line":36},[33,2895,2896],{"class":39},"# ── timeout runs a command with a time limit ──\n",[33,2898,2899,2901,2904,2907],{"class":35,"line":43},[33,2900,2883],{"class":46},[33,2902,2903],{"class":110}," 30",[33,2905,2906],{"class":114}," .\u002Fslow_script.sh",[33,2908,2909],{"class":39},"        # kill after 30s (SIGTERM)\n",[33,2911,2912,2914,2916,2919,2921,2924],{"class":35,"line":53},[33,2913,2883],{"class":46},[33,2915,2652],{"class":110},[33,2917,2918],{"class":114}," KILL",[33,2920,2903],{"class":110},[33,2922,2923],{"class":114}," .\u002Fslow.sh",[33,2925,2926],{"class":39},"       # use SIGKILL after 30s\n",[33,2928,2929,2931,2934,2936,2938,2940],{"class":35,"line":60},[33,2930,2883],{"class":46},[33,2932,2933],{"class":110}," -k",[33,2935,745],{"class":110},[33,2937,2903],{"class":110},[33,2939,2923],{"class":114},[33,2941,2942],{"class":39},"          # SIGTERM after 30s, then SIGKILL after 5 more if still running\n",[33,2944,2945,2947,2950,2952,2955],{"class":35,"line":66},[33,2946,2883],{"class":46},[33,2948,2949],{"class":110}," --preserve-status",[33,2951,2903],{"class":110},[33,2953,2954],{"class":114}," .\u002Fscript.sh",[33,2956,2957],{"class":39},"  # preserve the command's exit status (not 124)\n",[33,2959,2960],{"class":35,"line":75},[33,2961,57],{"emptyLinePlaceholder":56},[33,2963,2964],{"class":35,"line":81},[33,2965,2966],{"class":39},"# ── Exit codes ──\n",[33,2968,2969],{"class":35,"line":87},[33,2970,2971],{"class":39},"# timeout returns 124 if the command timed out, or the command's own exit status otherwise.\n",[33,2973,2974],{"class":35,"line":92},[33,2975,2976],{"class":39},"# Distinguish:\n",[33,2978,2979,2981,2983],{"class":35,"line":98},[33,2980,2883],{"class":46},[33,2982,2903],{"class":110},[33,2984,2985],{"class":114}," .\u002Fslow.sh\n",[33,2987,2988,2990,2992],{"class":35,"line":107},[33,2989,458],{"class":71},[33,2991,179],{"class":178},[33,2993,463],{"class":110},[33,2995,2996,2998,3001,3003,3006,3008],{"class":35,"line":121},[33,2997,625],{"class":178},[33,2999,3000],{"class":71}," ((status ",[33,3002,631],{"class":178},[33,3004,3005],{"class":110}," 124",[33,3007,656],{"class":71},[33,3009,659],{"class":178},[33,3011,3012,3014],{"class":35,"line":139},[33,3013,124],{"class":110},[33,3015,3016],{"class":114}," \"timed out\"\n",[33,3018,3019,3022,3024,3026,3029,3031],{"class":35,"line":145},[33,3020,3021],{"class":178},"elif",[33,3023,3000],{"class":71},[33,3025,631],{"class":178},[33,3027,3028],{"class":110}," 137",[33,3030,656],{"class":71},[33,3032,659],{"class":178},[33,3034,3035,3037],{"class":35,"line":161},[33,3036,124],{"class":110},[33,3038,3039],{"class":114}," \"killed (SIGKILL after timeout + grace period)\"\n",[33,3041,3042],{"class":35,"line":166},[33,3043,671],{"class":178},[33,3045,3046,3048,3051,3053],{"class":35,"line":172},[33,3047,124],{"class":110},[33,3049,3050],{"class":114}," \"exit: ",[33,3052,473],{"class":71},[33,3054,434],{"class":114},[33,3056,3057],{"class":35,"line":185},[33,3058,708],{"class":178},[33,3060,3061],{"class":35,"line":221},[33,3062,57],{"emptyLinePlaceholder":56},[33,3064,3065],{"class":35,"line":236},[33,3066,3067],{"class":39},"# ── Timeout with retry ──\n",[33,3069,3070,3073],{"class":35,"line":250},[33,3071,3072],{"class":46},"retry_with_timeout",[33,3074,1302],{"class":71},[33,3076,3077,3079,3082,3084,3087,3090,3092,3095,3097,3100],{"class":35,"line":255},[33,3078,1701],{"class":178},[33,3080,3081],{"class":71}," max",[33,3083,179],{"class":178},[33,3085,3086],{"class":2492},"$1",[33,3088,3089],{"class":71}," t",[33,3091,179],{"class":178},[33,3093,3094],{"class":2492},"$2",[33,3096,201],{"class":71},[33,3098,3099],{"class":110},"shift",[33,3101,3102],{"class":110}," 2\n",[33,3104,3105,3107,3110,3112],{"class":35,"line":261},[33,3106,1701],{"class":178},[33,3108,3109],{"class":71}," attempt",[33,3111,179],{"class":178},[33,3113,3114],{"class":110},"1\n",[33,3116,3117,3120,3123,3126,3129],{"class":35,"line":286},[33,3118,3119],{"class":178},"    while",[33,3121,3122],{"class":71}," ((attempt ",[33,3124,3125],{"class":178},"\u003C=",[33,3127,3128],{"class":71}," max)); ",[33,3130,750],{"class":178},[33,3132,3133,3136,3138,3141,3143,3145,3148,3150,3153,3156],{"class":35,"line":291},[33,3134,3135],{"class":46},"        timeout",[33,3137,206],{"class":114},[33,3139,3140],{"class":71},"$t",[33,3142,212],{"class":114},[33,3144,206],{"class":114},[33,3146,3147],{"class":110},"$@",[33,3149,212],{"class":114},[33,3151,3152],{"class":71}," && ",[33,3154,3155],{"class":178},"return",[33,3157,3158],{"class":110}," 0\n",[33,3160,3161,3164,3166,3168],{"class":35,"line":297},[33,3162,3163],{"class":178},"        local",[33,3165,1704],{"class":71},[33,3167,179],{"class":178},[33,3169,463],{"class":110},[33,3171,3172,3175,3177,3179,3182,3184,3187,3190,3193],{"class":35,"line":309},[33,3173,3174],{"class":71},"        ((code ",[33,3176,631],{"class":178},[33,3178,3005],{"class":110},[33,3180,3181],{"class":71},")) && ",[33,3183,148],{"class":110},[33,3185,3186],{"class":114}," \"attempt ",[33,3188,3189],{"class":71},"$attempt",[33,3191,3192],{"class":114},": timed out\"",[33,3194,1312],{"class":178},[33,3196,3197,3199,3202,3204,3206,3208,3210,3212,3215,3217,3219],{"class":35,"line":320},[33,3198,3174],{"class":71},[33,3200,3201],{"class":178},"!=",[33,3203,3005],{"class":110},[33,3205,3181],{"class":71},[33,3207,148],{"class":110},[33,3209,3186],{"class":114},[33,3211,3189],{"class":71},[33,3213,3214],{"class":114},": exit ",[33,3216,1731],{"class":71},[33,3218,212],{"class":114},[33,3220,1312],{"class":178},[33,3222,3223,3226,3228],{"class":35,"line":329},[33,3224,3225],{"class":71},"        ((attempt",[33,3227,2818],{"class":178},[33,3229,2821],{"class":71},[33,3231,3232,3235],{"class":35,"line":341},[33,3233,3234],{"class":46},"        sleep",[33,3236,3102],{"class":110},[33,3238,3239],{"class":35,"line":352},[33,3240,3241],{"class":178},"    done\n",[33,3243,3244,3247],{"class":35,"line":363},[33,3245,3246],{"class":178},"    return",[33,3248,703],{"class":110},[33,3250,3251],{"class":35,"line":374},[33,3252,1399],{"class":71},[33,3254,3255,3257,3259,3261,3264,3266,3268,3270],{"class":35,"line":715},[33,3256,3072],{"class":46},[33,3258,739],{"class":110},[33,3260,2903],{"class":110},[33,3262,3263],{"class":114}," curl",[33,3265,2652],{"class":110},[33,3267,206],{"class":114},[33,3269,2657],{"class":71},[33,3271,434],{"class":114},[15,3273,3275,3278,3279,3278,3282,3285],{"id":3274},"nohup-disown-setsid-detaching-from-the-terminal",[30,3276,3277],{},"nohup",", ",[30,3280,3281],{},"disown",[30,3283,3284],{},"setsid",": Detaching from the Terminal",[20,3287,3288],{"language":22},[24,3289,3291],{"className":26,"code":3290,"language":22,"meta":28,"style":28},"# ── Background jobs die when the terminal closes (SIGHUP) ──\n.\u002Flong_job.sh &       # if the terminal closes, the job gets SIGHUP and dies\n\n# ── nohup: immune to SIGHUP ──\nnohup .\u002Flong_job.sh &  # survives terminal close (SIGHUP is ignored)\n# stdout → nohup.out (if stdout is a terminal), stderr → stdout\n# Best practice: redirect explicitly:\nnohup .\u002Flong_job.sh > \u002Ftmp\u002Fjob.log 2>&1 &\ndisown                 # also remove from job table (so the shell doesn't warn on exit)\n\n# ── disown: remove a job from the shell's job table ──\n.\u002Fjob.sh &\ndisown                  # job is no longer in the job table — shell won't send SIGHUP on exit\n# disown -h: don't send SIGHUP on shell exit (keep in job table but ignore SIGHUP)\n\n# ── setsid: start in a new session (fully detached) ──\nsetsid .\u002Fjob.sh &      # job runs in a new session — no controlling terminal\n# More thorough than nohup — the job is fully detached from the terminal.\n\n# ── For production: use a process manager (systemd, supervisord) ──\n# systemd service file (\u002Fetc\u002Fsystemd\u002Fsystem\u002Fmyapp.service):\n# [Service]\n# ExecStart=\u002Fopt\u002Fmyapp\u002Fserver.sh\n# Restart=always\n# User=myapp\n",[30,3292,3293,3298,3309,3313,3318,3330,3335,3340,3357,3364,3368,3373,3380,3387,3392,3396,3401,3414,3419,3423,3428,3433,3438,3443,3448],{"__ignoreMap":28},[33,3294,3295],{"class":35,"line":36},[33,3296,3297],{"class":39},"# ── Background jobs die when the terminal closes (SIGHUP) ──\n",[33,3299,3300,3303,3306],{"class":35,"line":43},[33,3301,3302],{"class":46},".\u002Flong_job.sh",[33,3304,3305],{"class":71}," &       ",[33,3307,3308],{"class":39},"# if the terminal closes, the job gets SIGHUP and dies\n",[33,3310,3311],{"class":35,"line":53},[33,3312,57],{"emptyLinePlaceholder":56},[33,3314,3315],{"class":35,"line":60},[33,3316,3317],{"class":39},"# ── nohup: immune to SIGHUP ──\n",[33,3319,3320,3322,3325,3327],{"class":35,"line":66},[33,3321,3277],{"class":46},[33,3323,3324],{"class":114}," .\u002Flong_job.sh",[33,3326,2662],{"class":71},[33,3328,3329],{"class":39},"# survives terminal close (SIGHUP is ignored)\n",[33,3331,3332],{"class":35,"line":75},[33,3333,3334],{"class":39},"# stdout → nohup.out (if stdout is a terminal), stderr → stdout\n",[33,3336,3337],{"class":35,"line":81},[33,3338,3339],{"class":39},"# Best practice: redirect explicitly:\n",[33,3341,3342,3344,3346,3349,3352,3355],{"class":35,"line":87},[33,3343,3277],{"class":46},[33,3345,3324],{"class":114},[33,3347,3348],{"class":178}," >",[33,3350,3351],{"class":114}," \u002Ftmp\u002Fjob.log",[33,3353,3354],{"class":178}," 2>&1",[33,3356,72],{"class":71},[33,3358,3359,3361],{"class":35,"line":92},[33,3360,3281],{"class":110},[33,3362,3363],{"class":39},"                 # also remove from job table (so the shell doesn't warn on exit)\n",[33,3365,3366],{"class":35,"line":98},[33,3367,57],{"emptyLinePlaceholder":56},[33,3369,3370],{"class":35,"line":107},[33,3371,3372],{"class":39},"# ── disown: remove a job from the shell's job table ──\n",[33,3374,3375,3378],{"class":35,"line":121},[33,3376,3377],{"class":46},".\u002Fjob.sh",[33,3379,72],{"class":71},[33,3381,3382,3384],{"class":35,"line":139},[33,3383,3281],{"class":110},[33,3385,3386],{"class":39},"                  # job is no longer in the job table — shell won't send SIGHUP on exit\n",[33,3388,3389],{"class":35,"line":145},[33,3390,3391],{"class":39},"# disown -h: don't send SIGHUP on shell exit (keep in job table but ignore SIGHUP)\n",[33,3393,3394],{"class":35,"line":161},[33,3395,57],{"emptyLinePlaceholder":56},[33,3397,3398],{"class":35,"line":166},[33,3399,3400],{"class":39},"# ── setsid: start in a new session (fully detached) ──\n",[33,3402,3403,3405,3408,3411],{"class":35,"line":172},[33,3404,3284],{"class":46},[33,3406,3407],{"class":114}," .\u002Fjob.sh",[33,3409,3410],{"class":71}," &      ",[33,3412,3413],{"class":39},"# job runs in a new session — no controlling terminal\n",[33,3415,3416],{"class":35,"line":185},[33,3417,3418],{"class":39},"# More thorough than nohup — the job is fully detached from the terminal.\n",[33,3420,3421],{"class":35,"line":221},[33,3422,57],{"emptyLinePlaceholder":56},[33,3424,3425],{"class":35,"line":236},[33,3426,3427],{"class":39},"# ── For production: use a process manager (systemd, supervisord) ──\n",[33,3429,3430],{"class":35,"line":250},[33,3431,3432],{"class":39},"# systemd service file (\u002Fetc\u002Fsystemd\u002Fsystem\u002Fmyapp.service):\n",[33,3434,3435],{"class":35,"line":255},[33,3436,3437],{"class":39},"# [Service]\n",[33,3439,3440],{"class":35,"line":261},[33,3441,3442],{"class":39},"# ExecStart=\u002Fopt\u002Fmyapp\u002Fserver.sh\n",[33,3444,3445],{"class":35,"line":286},[33,3446,3447],{"class":39},"# Restart=always\n",[33,3449,3450],{"class":35,"line":291},[33,3451,3452],{"class":39},"# User=myapp\n",[15,3454,3456],{"id":3455},"process-inspection","Process Inspection",[20,3458,3459],{"language":22},[24,3460,3462],{"className":26,"code":3461,"language":22,"meta":28,"style":28},"# ── ps: list processes ──\nps aux              # all processes (BSD syntax: a=all, u=user format, x=no tty)\nps -ef              # all processes (POSIX syntax)\nps -fp $pid         # details for a specific PID\nps aux | grep bash  # find bash processes (includes the grep itself — use [b]ash trick)\nps aux | grep '[b]ash'  # [b]ash matches \"bash\" but not \"[b]ash\" (hides the grep process)\n\n# ── pgrep: find PIDs by name (no grep subprocess, no self-match issue) ──\npgrep -f \"script.sh\"    # PIDs matching \"script.sh\" in the command line\npgrep -f \"script.sh\" -a # PIDs + full command line\npgrep -u root bash      # PIDs owned by root running bash\n\n# ── pkill: kill by name ──\npkill -f \"script.sh\"    # SIGTERM all processes matching \"script.sh\"\npkill -9 -f \"script.sh\" # SIGKILL all matching (force)\npkill -u user bash      # kill all bash processes for a user\n\n# ── pstree: process tree ──\npstree -p              # tree with PIDs\npstree -p $pid         # tree starting from a specific PID\n\n# ── top \u002F htop: interactive monitors ──\ntop                    # built-in\nhtop                   # better (install separately: brew install htop)\n# htop features: tree view (F5), kill (F9), filter, sort by CPU\u002Fmemory\n",[30,3463,3464,3469,3480,3490,3502,3518,3534,3538,3543,3556,3569,3584,3588,3593,3605,3618,3632,3636,3641,3652,3663,3667,3672,3680,3688],{"__ignoreMap":28},[33,3465,3466],{"class":35,"line":36},[33,3467,3468],{"class":39},"# ── ps: list processes ──\n",[33,3470,3471,3474,3477],{"class":35,"line":43},[33,3472,3473],{"class":46},"ps",[33,3475,3476],{"class":114}," aux",[33,3478,3479],{"class":39},"              # all processes (BSD syntax: a=all, u=user format, x=no tty)\n",[33,3481,3482,3484,3487],{"class":35,"line":53},[33,3483,3473],{"class":46},[33,3485,3486],{"class":110}," -ef",[33,3488,3489],{"class":39},"              # all processes (POSIX syntax)\n",[33,3491,3492,3494,3497,3499],{"class":35,"line":60},[33,3493,3473],{"class":46},[33,3495,3496],{"class":110}," -fp",[33,3498,1158],{"class":71},[33,3500,3501],{"class":39},"# details for a specific PID\n",[33,3503,3504,3506,3508,3510,3512,3515],{"class":35,"line":66},[33,3505,3473],{"class":46},[33,3507,3476],{"class":114},[33,3509,2271],{"class":178},[33,3511,2301],{"class":46},[33,3513,3514],{"class":114}," bash",[33,3516,3517],{"class":39},"  # find bash processes (includes the grep itself — use [b]ash trick)\n",[33,3519,3520,3522,3524,3526,3528,3531],{"class":35,"line":75},[33,3521,3473],{"class":46},[33,3523,3476],{"class":114},[33,3525,2271],{"class":178},[33,3527,2301],{"class":46},[33,3529,3530],{"class":114}," '[b]ash'",[33,3532,3533],{"class":39},"  # [b]ash matches \"bash\" but not \"[b]ash\" (hides the grep process)\n",[33,3535,3536],{"class":35,"line":81},[33,3537,57],{"emptyLinePlaceholder":56},[33,3539,3540],{"class":35,"line":87},[33,3541,3542],{"class":39},"# ── pgrep: find PIDs by name (no grep subprocess, no self-match issue) ──\n",[33,3544,3545,3548,3550,3553],{"class":35,"line":92},[33,3546,3547],{"class":46},"pgrep",[33,3549,1336],{"class":110},[33,3551,3552],{"class":114}," \"script.sh\"",[33,3554,3555],{"class":39},"    # PIDs matching \"script.sh\" in the command line\n",[33,3557,3558,3560,3562,3564,3566],{"class":35,"line":98},[33,3559,3547],{"class":46},[33,3561,1336],{"class":110},[33,3563,3552],{"class":114},[33,3565,2693],{"class":110},[33,3567,3568],{"class":39}," # PIDs + full command line\n",[33,3570,3571,3573,3576,3579,3581],{"class":35,"line":107},[33,3572,3547],{"class":46},[33,3574,3575],{"class":110}," -u",[33,3577,3578],{"class":114}," root",[33,3580,3514],{"class":114},[33,3582,3583],{"class":39},"      # PIDs owned by root running bash\n",[33,3585,3586],{"class":35,"line":121},[33,3587,57],{"emptyLinePlaceholder":56},[33,3589,3590],{"class":35,"line":139},[33,3591,3592],{"class":39},"# ── pkill: kill by name ──\n",[33,3594,3595,3598,3600,3602],{"class":35,"line":145},[33,3596,3597],{"class":46},"pkill",[33,3599,1336],{"class":110},[33,3601,3552],{"class":114},[33,3603,3604],{"class":39},"    # SIGTERM all processes matching \"script.sh\"\n",[33,3606,3607,3609,3611,3613,3615],{"class":35,"line":161},[33,3608,3597],{"class":46},[33,3610,1155],{"class":110},[33,3612,1336],{"class":110},[33,3614,3552],{"class":114},[33,3616,3617],{"class":39}," # SIGKILL all matching (force)\n",[33,3619,3620,3622,3624,3627,3629],{"class":35,"line":166},[33,3621,3597],{"class":46},[33,3623,3575],{"class":110},[33,3625,3626],{"class":114}," user",[33,3628,3514],{"class":114},[33,3630,3631],{"class":39},"      # kill all bash processes for a user\n",[33,3633,3634],{"class":35,"line":172},[33,3635,57],{"emptyLinePlaceholder":56},[33,3637,3638],{"class":35,"line":185},[33,3639,3640],{"class":39},"# ── pstree: process tree ──\n",[33,3642,3643,3646,3649],{"class":35,"line":221},[33,3644,3645],{"class":46},"pstree",[33,3647,3648],{"class":110}," -p",[33,3650,3651],{"class":39},"              # tree with PIDs\n",[33,3653,3654,3656,3658,3660],{"class":35,"line":236},[33,3655,3645],{"class":46},[33,3657,3648],{"class":110},[33,3659,1158],{"class":71},[33,3661,3662],{"class":39},"# tree starting from a specific PID\n",[33,3664,3665],{"class":35,"line":250},[33,3666,57],{"emptyLinePlaceholder":56},[33,3668,3669],{"class":35,"line":255},[33,3670,3671],{"class":39},"# ── top \u002F htop: interactive monitors ──\n",[33,3673,3674,3677],{"class":35,"line":261},[33,3675,3676],{"class":46},"top",[33,3678,3679],{"class":39},"                    # built-in\n",[33,3681,3682,3685],{"class":35,"line":286},[33,3683,3684],{"class":46},"htop",[33,3686,3687],{"class":39},"                   # better (install separately: brew install htop)\n",[33,3689,3690],{"class":35,"line":291},[33,3691,3692],{"class":39},"# htop features: tree view (F5), kill (F9), filter, sort by CPU\u002Fmemory\n",[15,3694,3696],{"id":3695},"tips-tricks","💡 Tips & Tricks",[20,3698,3699],{"language":22},[24,3700,3702],{"className":26,"code":3701,"language":22,"meta":28,"style":28},"# ── Job pool pattern: limit parallelism with wait -n (Bash 5.1+) ──\nmax_jobs=4\nrunning=0\nfor task in \"${tasks[@]}\"; do\n    .\u002Fworker.sh \"$task\" &\n    ((running++))\n    ((running >= max_jobs)) && { wait -n; ((running--)); }\ndone\nwait  # wait for remaining jobs\n\n# ── Portable job pool (no wait -n, works on older Bash) ──\nmax_jobs=4\npids=()\nfor task in \"${tasks[@]}\"; do\n    .\u002Fworker.sh \"$task\" &\n    pids+=($!)\n    (( ${#pids[@]} >= max_jobs )) && {\n        # Wait for any one to finish, remove it from the array\n        for i in \"${!pids[@]}\"; do\n            if ! kill -0 \"${pids[i]}\" 2>\u002Fdev\u002Fnull; then\n                wait \"${pids[i]}\"  # reap the zombie\n                unset 'pids[i]'\n                pids=(\"${pids[@]}\")  # reindex\n                break\n            fi\n        done\n    }\ndone\nwait  # wait for remaining\n\n# ── Check if a process is alive ──\nif kill -0 \"$pid\" 2>\u002Fdev\u002Fnull; then\n    echo \"process $pid is running\"\nelse\n    echo \"process $pid is dead\"\nfi\n# kill -0 sends signal 0 (no actual signal) — just checks if the process exists.\n\n# ── Coprocess (Bash 4+) ──\ncoproc sql { sqlite3 mydb.db; }   # start a coprocess with bidirectional pipe\necho \"SELECT 1+1;\" >&\"${sql[1]}\"  # write to coprocess stdin (fd in sql[1])\nread -r result \u003C&\"${sql[0]}\"      # read from coprocess stdout (fd in sql[0])\necho \"result: $result\"            # \"2\"\n",[30,3703,3704,3709,3719,3728,3752,3765,3774,3798,3802,3809,3813,3818,3826,3834,3856,3868,3880,3900,3905,3930,3957,3971,3979,4005,4010,4015,4019,4024,4028,4035,4039,4044,4066,4078,4082,4093,4097,4102,4106,4111,4128,4149,4176],{"__ignoreMap":28},[33,3705,3706],{"class":35,"line":36},[33,3707,3708],{"class":39},"# ── Job pool pattern: limit parallelism with wait -n (Bash 5.1+) ──\n",[33,3710,3711,3714,3716],{"class":35,"line":43},[33,3712,3713],{"class":71},"max_jobs",[33,3715,179],{"class":178},[33,3717,3718],{"class":114},"4\n",[33,3720,3721,3724,3726],{"class":35,"line":53},[33,3722,3723],{"class":71},"running",[33,3725,179],{"class":178},[33,3727,2778],{"class":114},[33,3729,3730,3732,3735,3737,3739,3742,3744,3746,3748,3750],{"class":35,"line":60},[33,3731,724],{"class":178},[33,3733,3734],{"class":71}," task ",[33,3736,730],{"class":178},[33,3738,966],{"class":114},[33,3740,3741],{"class":71},"tasks",[33,3743,971],{"class":114},[33,3745,974],{"class":178},[33,3747,977],{"class":114},[33,3749,201],{"class":71},[33,3751,750],{"class":178},[33,3753,3754,3756,3758,3761,3763],{"class":35,"line":66},[33,3755,756],{"class":46},[33,3757,206],{"class":114},[33,3759,3760],{"class":71},"$task",[33,3762,212],{"class":114},[33,3764,72],{"class":71},[33,3766,3767,3770,3772],{"class":35,"line":75},[33,3768,3769],{"class":71},"    ((running",[33,3771,2818],{"class":178},[33,3773,2821],{"class":71},[33,3775,3776,3779,3782,3785,3787,3789,3792,3795],{"class":35,"line":81},[33,3777,3778],{"class":71},"    ((running ",[33,3780,3781],{"class":178},">=",[33,3783,3784],{"class":71}," max_jobs)) && { ",[33,3786,377],{"class":110},[33,3788,779],{"class":110},[33,3790,3791],{"class":71},"; ((running",[33,3793,3794],{"class":178},"--",[33,3796,3797],{"class":71},")); }\n",[33,3799,3800],{"class":35,"line":87},[33,3801,771],{"class":178},[33,3803,3804,3806],{"class":35,"line":92},[33,3805,377],{"class":110},[33,3807,3808],{"class":39},"  # wait for remaining jobs\n",[33,3810,3811],{"class":35,"line":98},[33,3812,57],{"emptyLinePlaceholder":56},[33,3814,3815],{"class":35,"line":107},[33,3816,3817],{"class":39},"# ── Portable job pool (no wait -n, works on older Bash) ──\n",[33,3819,3820,3822,3824],{"class":35,"line":121},[33,3821,3713],{"class":71},[33,3823,179],{"class":178},[33,3825,3718],{"class":114},[33,3827,3828,3830,3832],{"class":35,"line":139},[33,3829,890],{"class":71},[33,3831,179],{"class":178},[33,3833,895],{"class":71},[33,3835,3836,3838,3840,3842,3844,3846,3848,3850,3852,3854],{"class":35,"line":145},[33,3837,724],{"class":178},[33,3839,3734],{"class":71},[33,3841,730],{"class":178},[33,3843,966],{"class":114},[33,3845,3741],{"class":71},[33,3847,971],{"class":114},[33,3849,974],{"class":178},[33,3851,977],{"class":114},[33,3853,201],{"class":71},[33,3855,750],{"class":178},[33,3857,3858,3860,3862,3864,3866],{"class":35,"line":161},[33,3859,756],{"class":46},[33,3861,206],{"class":114},[33,3863,3760],{"class":71},[33,3865,212],{"class":114},[33,3867,72],{"class":71},[33,3869,3870,3872,3874,3876,3878],{"class":35,"line":166},[33,3871,2752],{"class":71},[33,3873,905],{"class":178},[33,3875,908],{"class":71},[33,3877,386],{"class":110},[33,3879,142],{"class":71},[33,3881,3882,3885,3887,3890,3892,3895,3897],{"class":35,"line":172},[33,3883,3884],{"class":71},"    (( ${",[33,3886,2857],{"class":178},[33,3888,3889],{"class":71},"pids[",[33,3891,974],{"class":178},[33,3893,3894],{"class":71},"]} ",[33,3896,3781],{"class":178},[33,3898,3899],{"class":71}," max_jobs )) && {\n",[33,3901,3902],{"class":35,"line":185},[33,3903,3904],{"class":39},"        # Wait for any one to finish, remove it from the array\n",[33,3906,3907,3909,3911,3913,3915,3918,3920,3922,3924,3926,3928],{"class":35,"line":221},[33,3908,1995],{"class":178},[33,3910,727],{"class":71},[33,3912,730],{"class":178},[33,3914,966],{"class":114},[33,3916,3917],{"class":178},"!",[33,3919,890],{"class":71},[33,3921,971],{"class":114},[33,3923,974],{"class":178},[33,3925,977],{"class":114},[33,3927,201],{"class":71},[33,3929,750],{"class":178},[33,3931,3932,3935,3938,3940,3942,3944,3946,3949,3951,3953,3955],{"class":35,"line":236},[33,3933,3934],{"class":178},"            if",[33,3936,3937],{"class":178}," !",[33,3939,2060],{"class":110},[33,3941,1215],{"class":110},[33,3943,966],{"class":114},[33,3945,890],{"class":71},[33,3947,3948],{"class":114},"[i]}\"",[33,3950,1368],{"class":178},[33,3952,1951],{"class":114},[33,3954,201],{"class":71},[33,3956,659],{"class":178},[33,3958,3959,3962,3964,3966,3968],{"class":35,"line":250},[33,3960,3961],{"class":110},"                wait",[33,3963,966],{"class":114},[33,3965,890],{"class":71},[33,3967,3948],{"class":114},[33,3969,3970],{"class":39},"  # reap the zombie\n",[33,3972,3973,3976],{"class":35,"line":255},[33,3974,3975],{"class":110},"                unset",[33,3977,3978],{"class":114}," 'pids[i]'\n",[33,3980,3981,3984,3986,3988,3991,3993,3995,3997,3999,4002],{"class":35,"line":261},[33,3982,3983],{"class":71},"                pids",[33,3985,179],{"class":178},[33,3987,908],{"class":71},[33,3989,3990],{"class":114},"\"${",[33,3992,890],{"class":71},[33,3994,971],{"class":114},[33,3996,974],{"class":178},[33,3998,977],{"class":114},[33,4000,4001],{"class":71},")  ",[33,4003,4004],{"class":39},"# reindex\n",[33,4006,4007],{"class":35,"line":286},[33,4008,4009],{"class":178},"                break\n",[33,4011,4012],{"class":35,"line":291},[33,4013,4014],{"class":178},"            fi\n",[33,4016,4017],{"class":35,"line":297},[33,4018,2043],{"class":178},[33,4020,4021],{"class":35,"line":309},[33,4022,4023],{"class":71},"    }\n",[33,4025,4026],{"class":35,"line":320},[33,4027,771],{"class":178},[33,4029,4030,4032],{"class":35,"line":329},[33,4031,377],{"class":110},[33,4033,4034],{"class":39},"  # wait for remaining\n",[33,4036,4037],{"class":35,"line":341},[33,4038,57],{"emptyLinePlaceholder":56},[33,4040,4041],{"class":35,"line":352},[33,4042,4043],{"class":39},"# ── Check if a process is alive ──\n",[33,4045,4046,4048,4050,4052,4054,4056,4058,4060,4062,4064],{"class":35,"line":363},[33,4047,625],{"class":178},[33,4049,2060],{"class":110},[33,4051,1215],{"class":110},[33,4053,206],{"class":114},[33,4055,431],{"class":71},[33,4057,212],{"class":114},[33,4059,1368],{"class":178},[33,4061,1951],{"class":114},[33,4063,201],{"class":71},[33,4065,659],{"class":178},[33,4067,4068,4070,4073,4075],{"class":35,"line":374},[33,4069,124],{"class":110},[33,4071,4072],{"class":114}," \"process ",[33,4074,431],{"class":71},[33,4076,4077],{"class":114}," is running\"\n",[33,4079,4080],{"class":35,"line":715},[33,4081,671],{"class":178},[33,4083,4084,4086,4088,4090],{"class":35,"line":721},[33,4085,124],{"class":110},[33,4087,4072],{"class":114},[33,4089,431],{"class":71},[33,4091,4092],{"class":114}," is dead\"\n",[33,4094,4095],{"class":35,"line":753},[33,4096,708],{"class":178},[33,4098,4099],{"class":35,"line":768},[33,4100,4101],{"class":39},"# kill -0 sends signal 0 (no actual signal) — just checks if the process exists.\n",[33,4103,4104],{"class":35,"line":774},[33,4105,57],{"emptyLinePlaceholder":56},[33,4107,4108],{"class":35,"line":785},[33,4109,4110],{"class":39},"# ── Coprocess (Bash 4+) ──\n",[33,4112,4113,4116,4119,4122,4125],{"class":35,"line":798},[33,4114,4115],{"class":71},"coproc sql { ",[33,4117,4118],{"class":46},"sqlite3",[33,4120,4121],{"class":114}," mydb.db",[33,4123,4124],{"class":71},"; }   ",[33,4126,4127],{"class":39},"# start a coprocess with bidirectional pipe\n",[33,4129,4130,4132,4135,4138,4140,4143,4146],{"class":35,"line":1641},[33,4131,148],{"class":110},[33,4133,4134],{"class":114}," \"SELECT 1+1;\"",[33,4136,4137],{"class":178}," >&",[33,4139,3990],{"class":114},[33,4141,4142],{"class":71},"sql",[33,4144,4145],{"class":114},"[1]}\"",[33,4147,4148],{"class":39},"  # write to coprocess stdin (fd in sql[1])\n",[33,4150,4151,4154,4157,4160,4163,4166,4168,4170,4173],{"class":35,"line":1646},[33,4152,4153],{"class":110},"read",[33,4155,4156],{"class":110}," -r",[33,4158,4159],{"class":114}," result",[33,4161,4162],{"class":178}," \u003C",[33,4164,4165],{"class":71},"&",[33,4167,3990],{"class":46},[33,4169,4142],{"class":71},[33,4171,4172],{"class":46},"[0]}\"",[33,4174,4175],{"class":39},"      # read from coprocess stdout (fd in sql[0])\n",[33,4177,4178,4180,4183,4186,4188],{"class":35,"line":1652},[33,4179,148],{"class":110},[33,4181,4182],{"class":114}," \"result: ",[33,4184,4185],{"class":71},"$result",[33,4187,212],{"class":114},[33,4189,4190],{"class":39},"            # \"2\"\n",[15,4192,4194],{"id":4193},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,4196,4197],{"language":22},[24,4198,4200],{"className":26,"code":4199,"language":22,"meta":28,"style":28},"# ── `kill -9` can't be caught — no cleanup runs ──\n# The process is immediately terminated by the kernel. No trap, no EXIT, no cleanup.\n# Always try SIGTERM first: kill $pid; sleep 5; kill -9 $pid\n\n# ── `$!` changes with each new background command ──\n# Capture it immediately: cmd &; pid=$!\n# If you run another cmd & in between, $! is the new command's PID.\n\n# ── `wait` only works for jobs of the CURRENT shell ──\n# In a subshell: ( cmd & ); wait  → fails (the subshell's job is gone after it exits)\n# Run wait inside the subshell: ( cmd &; wait )  → works\n\n# ── `trap` in a subshell doesn't affect the parent ──\n# ( trap 'echo sub' EXIT; echo \"in sub\" )  → the parent's EXIT trap is unchanged.\n\n# ── `trap EXIT` fires ONCE ──\n# On exit, the EXIT trap runs once. If you set multiple trap EXIT, last one wins.\n# Combine all cleanup in one function: trap 'cleanup_all' EXIT\n\n# ── `timeout` exit code 124 means \"timed out\" ──\n# But 124 could also be the command's own exit code (if it happens to exit 124).\n# Distinguish: `timeout --preserve-status` returns the command's real exit code.\n\n# ── `nohup` redirects to nohup.out if stdout is a terminal ──\n# If stdout is not a terminal (piped, redirected), nohup doesn't create nohup.out.\n# Always redirect explicitly: nohup cmd > \u002Ftmp\u002Flog 2>&1 &\n\n# ── Zombie processes ──\n# A child that exits but isn't `wait`ed becomes a zombie (defunct process).\n# The parent must `wait` to reap it. If the parent exits, init (PID 1) reaps it.\n# In scripts, `wait` at the end reaps all children. In long-running scripts, `wait -n` periodically.\n",[30,4201,4202,4207,4212,4217,4221,4226,4231,4236,4240,4245,4250,4255,4259,4264,4269,4273,4278,4283,4288,4292,4297,4302,4307,4311,4316,4321,4326,4330,4335,4340,4345],{"__ignoreMap":28},[33,4203,4204],{"class":35,"line":36},[33,4205,4206],{"class":39},"# ── `kill -9` can't be caught — no cleanup runs ──\n",[33,4208,4209],{"class":35,"line":43},[33,4210,4211],{"class":39},"# The process is immediately terminated by the kernel. No trap, no EXIT, no cleanup.\n",[33,4213,4214],{"class":35,"line":53},[33,4215,4216],{"class":39},"# Always try SIGTERM first: kill $pid; sleep 5; kill -9 $pid\n",[33,4218,4219],{"class":35,"line":60},[33,4220,57],{"emptyLinePlaceholder":56},[33,4222,4223],{"class":35,"line":66},[33,4224,4225],{"class":39},"# ── `$!` changes with each new background command ──\n",[33,4227,4228],{"class":35,"line":75},[33,4229,4230],{"class":39},"# Capture it immediately: cmd &; pid=$!\n",[33,4232,4233],{"class":35,"line":81},[33,4234,4235],{"class":39},"# If you run another cmd & in between, $! is the new command's PID.\n",[33,4237,4238],{"class":35,"line":87},[33,4239,57],{"emptyLinePlaceholder":56},[33,4241,4242],{"class":35,"line":92},[33,4243,4244],{"class":39},"# ── `wait` only works for jobs of the CURRENT shell ──\n",[33,4246,4247],{"class":35,"line":98},[33,4248,4249],{"class":39},"# In a subshell: ( cmd & ); wait  → fails (the subshell's job is gone after it exits)\n",[33,4251,4252],{"class":35,"line":107},[33,4253,4254],{"class":39},"# Run wait inside the subshell: ( cmd &; wait )  → works\n",[33,4256,4257],{"class":35,"line":121},[33,4258,57],{"emptyLinePlaceholder":56},[33,4260,4261],{"class":35,"line":139},[33,4262,4263],{"class":39},"# ── `trap` in a subshell doesn't affect the parent ──\n",[33,4265,4266],{"class":35,"line":145},[33,4267,4268],{"class":39},"# ( trap 'echo sub' EXIT; echo \"in sub\" )  → the parent's EXIT trap is unchanged.\n",[33,4270,4271],{"class":35,"line":161},[33,4272,57],{"emptyLinePlaceholder":56},[33,4274,4275],{"class":35,"line":166},[33,4276,4277],{"class":39},"# ── `trap EXIT` fires ONCE ──\n",[33,4279,4280],{"class":35,"line":172},[33,4281,4282],{"class":39},"# On exit, the EXIT trap runs once. If you set multiple trap EXIT, last one wins.\n",[33,4284,4285],{"class":35,"line":185},[33,4286,4287],{"class":39},"# Combine all cleanup in one function: trap 'cleanup_all' EXIT\n",[33,4289,4290],{"class":35,"line":221},[33,4291,57],{"emptyLinePlaceholder":56},[33,4293,4294],{"class":35,"line":236},[33,4295,4296],{"class":39},"# ── `timeout` exit code 124 means \"timed out\" ──\n",[33,4298,4299],{"class":35,"line":250},[33,4300,4301],{"class":39},"# But 124 could also be the command's own exit code (if it happens to exit 124).\n",[33,4303,4304],{"class":35,"line":255},[33,4305,4306],{"class":39},"# Distinguish: `timeout --preserve-status` returns the command's real exit code.\n",[33,4308,4309],{"class":35,"line":261},[33,4310,57],{"emptyLinePlaceholder":56},[33,4312,4313],{"class":35,"line":286},[33,4314,4315],{"class":39},"# ── `nohup` redirects to nohup.out if stdout is a terminal ──\n",[33,4317,4318],{"class":35,"line":291},[33,4319,4320],{"class":39},"# If stdout is not a terminal (piped, redirected), nohup doesn't create nohup.out.\n",[33,4322,4323],{"class":35,"line":297},[33,4324,4325],{"class":39},"# Always redirect explicitly: nohup cmd > \u002Ftmp\u002Flog 2>&1 &\n",[33,4327,4328],{"class":35,"line":309},[33,4329,57],{"emptyLinePlaceholder":56},[33,4331,4332],{"class":35,"line":320},[33,4333,4334],{"class":39},"# ── Zombie processes ──\n",[33,4336,4337],{"class":35,"line":329},[33,4338,4339],{"class":39},"# A child that exits but isn't `wait`ed becomes a zombie (defunct process).\n",[33,4341,4342],{"class":35,"line":341},[33,4343,4344],{"class":39},"# The parent must `wait` to reap it. If the parent exits, init (PID 1) reaps it.\n",[33,4346,4347],{"class":35,"line":352},[33,4348,4349],{"class":39},"# In scripts, `wait` at the end reaps all children. In long-running scripts, `wait -n` periodically.\n",[15,4351,4353],{"id":4352},"quick-quiz","🧠 Quick Quiz",[4355,4356,4357,4358,4361],"p",{},"Why does this script not clean up when killed with ",[30,4359,4360],{},"kill -9","?",[20,4363,4364],{"language":22},[24,4365,4367],{"className":26,"code":4366,"language":22,"meta":28,"style":28},"cleanup() {\n    rm -f \"$tmpfile\"\n    echo \"cleaned up\" >&2\n}\ntmpfile=$(mktemp)\ntrap cleanup EXIT\necho \"working with $tmpfile\"\nsleep 60\n",[30,4368,4369,4375,4388,4397,4401,4413,4422,4433],{"__ignoreMap":28},[33,4370,4371,4373],{"class":35,"line":36},[33,4372,1299],{"class":46},[33,4374,1302],{"class":71},[33,4376,4377,4380,4382,4384,4386],{"class":35,"line":43},[33,4378,4379],{"class":46},"    rm",[33,4381,1336],{"class":110},[33,4383,206],{"class":114},[33,4385,1325],{"class":71},[33,4387,434],{"class":114},[33,4389,4390,4392,4395],{"class":35,"line":53},[33,4391,124],{"class":110},[33,4393,4394],{"class":114}," \"cleaned up\"",[33,4396,1312],{"class":178},[33,4398,4399],{"class":35,"line":60},[33,4400,1399],{"class":71},[33,4402,4403,4405,4407,4409,4411],{"class":35,"line":66},[33,4404,1408],{"class":71},[33,4406,179],{"class":178},[33,4408,1413],{"class":71},[33,4410,1416],{"class":46},[33,4412,142],{"class":71},[33,4414,4415,4417,4419],{"class":35,"line":75},[33,4416,1281],{"class":110},[33,4418,1435],{"class":114},[33,4420,4421],{"class":114}," EXIT\n",[33,4423,4424,4426,4429,4431],{"class":35,"line":81},[33,4425,148],{"class":110},[33,4427,4428],{"class":114}," \"working with ",[33,4430,1325],{"class":71},[33,4432,434],{"class":114},[33,4434,4435,4438],{"class":35,"line":87},[33,4436,4437],{"class":46},"sleep",[33,4439,4440],{"class":110}," 60\n",[4442,4443,4444,4448,4465,4471,4507],"details",{},[4445,4446,4447],"summary",{},"Answer",[4355,4449,4450,4452,4453,4457,4458,4461,4462,4464],{},[30,4451,4360],{}," sends ",[4454,4455,4456],"strong",{},"SIGKILL",", which ",[4454,4459,4460],{},"cannot be caught or handled",". The kernel terminates the process immediately — no trap runs, no cleanup function is called, ",[30,4463,1408],{}," is left on disk.",[4355,4466,4467,4470],{},[4454,4468,4469],{},"The fix",": There's no way to catch SIGKILL. The mitigations are:",[4472,4473,4474,4488,4498],"ol",{},[4475,4476,4477,4483,4484,4487],"li",{},[4454,4478,4479,4480,4482],{},"Use SIGTERM (default ",[30,4481,355],{},")"," — it CAN be trapped, and ",[30,4485,4486],{},"trap cleanup EXIT"," fires.",[4475,4489,4490,4493,4494,4497],{},[4454,4491,4492],{},"Clean up stale temp files on startup",": ",[30,4495,4496],{},"rm -f \u002Ftmp\u002Fmyapp.* 2>\u002Fdev\u002Fnull"," at the start.",[4475,4499,4500,4506],{},[4454,4501,4502,4503,4505],{},"Use ",[30,4504,1416],{}," with a recognizable prefix"," so you can find and clean up stale files later.",[4355,4508,4509,4512,4513,4515,4516,4518],{},[4454,4510,4511],{},"The lesson",": SIGKILL is the nuclear option — no cleanup. Always prefer SIGTERM (the default ",[30,4514,355],{}," command). Only use ",[30,4517,4360],{}," when the process is truly hung and ignoring SIGTERM.",[4520,4521,4522],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}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 .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}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 .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":28,"searchDepth":43,"depth":43,"links":4524},[4525,4526,4528,4530,4531,4533,4534,4536,4537,4539,4541,4542,4543,4544],{"id":17,"depth":43,"text":18},{"id":383,"depth":43,"text":4527},"$! and wait: Capturing Process PIDs and Exit Status",{"id":804,"depth":43,"text":4529},"Anti-Pattern: wait Without PIDs",{"id":1030,"depth":43,"text":1031},{"id":1278,"depth":43,"text":4532},"trap: Signal Handling for Graceful Shutdown",{"id":1778,"depth":43,"text":1779},{"id":2226,"depth":43,"text":4535},"xargs: Parallel Processing",{"id":2607,"depth":43,"text":2608},{"id":2880,"depth":43,"text":4538},"timeout: Enforcing Time Limits",{"id":3274,"depth":43,"text":4540},"nohup, disown, setsid: Detaching from the Terminal",{"id":3455,"depth":43,"text":3456},{"id":3695,"depth":43,"text":3696},{"id":4193,"depth":43,"text":4194},{"id":4352,"depth":43,"text":4353},"Deep-dive into Bash process lifecycle: background jobs, signal dispatch, trap mechanics, wait\u002Fn job pools, xargs parallelism, timeout enforcement, and production patterns for graceful shutdown. Code-first reference for senior engineers.","md",{},"\u002Fbash\u002F08-processes-and-signals",{"title":5,"description":4545},"bash\u002F08-processes-and-signals","vrZ0rIYU2Y64b-mwf9ISf9WqRh8RTG6IBLIE8Gog6pA",1789924644817]