SSD Nodes Learn 🎉 VPS $5.50/माह से
गाइड Matt Connorलेखक: Matt Connor

SSH disconnect होने पर कमांड चालू कैसे रखें

SSH कनेक्शन टूटने पर SIGHUP सिग्नल से आपकी प्रोसेस बंद हो जाती है। nohup, disown, tmux या systemd-run का उपयोग करके अपनी कमांड को बैकग्राउंड में सुरक्षित चलाने का सही तरीका जानें।

SSH डिस्कनेक्ट होने पर आपकी कमांड क्यों बंद हो जाती है

SSH डिस्कनेक्ट होने के बाद भी किसी कमांड को चालू रखने के लिए, उसे ऐसी जगह चलना चाहिए जहाँ hangup सिग्नल न पहुँच सके। नीचे दी गई प्रत्येक विधि इसे व्यवस्थित करने का एक अलग तरीका है, इसलिए तंत्र (mechanism) को समझना शुरू करें।

आपका लॉगिन एक pty (pseudo-terminal) पर चलता है, जो एक वर्चुअल टर्मिनल डिवाइस है जिसे sshd सर्वर पर आपके सत्र के लिए बनाता है। यह आपके शेल और उस शेल से शुरू की गई प्रत्येक कमांड का कंट्रोलिंग टर्मिनल होता है। यदि आप इस प्रक्रिया के बारे में विस्तार से जानना चाहते हैं, तो लॉगिन करने पर SSH क्या सेटअप करता है इसे देखें। जब TCP कनेक्शन टूटता है, तो sshd अपना सिरा बंद कर देता है और pty नष्ट हो जाता है। कर्नेल इसे टर्मिनल के हैंग होने के रूप में देखता है, इसलिए यह उस टर्मिनल के फोरग्राउंड प्रोसेस ग्रुप और सेशन लीडर (जो आपका शेल है) को SIGHUP भेजता है। SIGHUP के लिए डिफ़ॉल्ट क्रिया प्रक्रिया को समाप्त करना है। आपकी कमांड फोरग्राउंड प्रोसेस ग्रुप में थी, इसलिए आपकी कमांड बंद हो जाती है।

बैकग्राउंड जॉब्स भी सुरक्षित नहीं हैं। & के साथ शुरू की गई जॉब अपने स्वयं के प्रोसेस ग्रुप में होती है, इसलिए कर्नेल उसे सीधे सिग्नल नहीं भेजता है। लेकिन Bash ऐसा करता है। SIGHUP प्राप्त होने पर, एक इंटरैक्टिव bash बाहर निकलने से पहले अपनी टेबल में मौजूद हर जॉब को SIGHUP भेजता है। आपकी तरफ से परिणाम एक जैसा दिखता है: जॉब गायब हो जाती है और लॉग फ़ाइल बीच में ही रुक जाती है।

यहाँ एक विषमता (asymmetry) है जो लोगों को भ्रमित करती है। exit टाइप करने से आपकी बैकग्राउंड जॉब्स हैंग नहीं होती हैं, क्योंकि bash ऐसा केवल तब करता है जब huponexit विकल्प सेट हो, और यह डिफ़ॉल्ट रूप से बंद रहता है। कनेक्शन टूटने पर वे हैंग हो जाती हैं। जो जॉब आपके टर्मिनल को सामान्य रूप से बंद करने पर बच गई थी, वह वाईफाई ड्रॉप होने पर मर सकती है।

इसके दो परिणाम होते हैं, और यही पूरा विषय है। एक प्रक्रिया जो SIGHUP को अनदेखा करती है, या जिसका कोई कंट्रोलिंग टर्मिनल नहीं है, वह हैंग नहीं होगी। और जिस प्रक्रिया का स्टैंडर्ड आउटपुट अभी भी नष्ट हो चुके pty की ओर इशारा करता है, उसके पास लिखने के लिए कोई जगह नहीं होती: राइट ऑपरेशन EIO (input/output error) के साथ विफल हो जाता है, और अधिकांश प्रोग्राम उस बिंदु पर बंद हो जाते हैं। आपको दोनों समस्याओं का समाधान करना होगा। कई तरीके केवल पहले हिस्से को हल करते हैं, यही कारण है कि लोग कहते हैं कि "nohup काम नहीं कर रहा है"।

यदि आपका कनेक्शन दिन में कई बार टूटता है, तो इसे भी ठीक करें। ~/.ssh/config में ServerAliveInterval 60 का उपयोग करने से एक निष्क्रिय सत्र (idle session) रास्ते में कहीं NAT (network address translation) टाइमआउट द्वारा डिस्कनेक्ट होने से बच जाता है। एक सत्र जो बिल्कुल भी नहीं खुलता है, वह एक अलग समस्या है जिसके कारण अलग होते हैं, जहाँ connection refused और connection timed out के बीच का अंतर मायने रखता है।

SSH डिस्कनेक्ट होने के बाद कमांड को चालू रखने का कौन सा तरीका है?

चार उत्तर, कार्य की गंभीरता के क्रम में:

  • nohup या setsid: एक ऐसा कार्य जिसे आप अभी शुरू करते हैं और बाद में लॉग पढ़ते हैं। आप आउटपुट को स्वयं रीडायरेक्ट करते हैं।
  • disown: वह कार्य जिसे आप पहले ही शुरू कर चुके हैं और सुरक्षित करना भूल गए। यह प्रोसेस को रेस्क्यू करता है। यह आपको आउटपुट वापस नहीं दे सकता।
  • tmux or screen: वह कार्य जिसे आपको कई दिनों तक मॉनिटर करने, रोकने और वापस उस पर लौटने की आवश्यकता है।
  • systemd-run या एक वास्तविक unit file: कोई भी ऐसी चीज़ जिसे आपके लॉगिन से अधिक समय तक चलना चाहिए, जैसे कि छह घंटे का rsync या रात भर चलने वाला डेटाबेस इम्पोर्ट।

याद रखने योग्य नियम: यदि कार्य को भूल जाना एक समस्या बन सकता है, तो वह कार्य tmux का नहीं, बल्कि systemd का है। tmux विंडो एक ऐसी चीज़ है जिसे इंसान को याद रखना पड़ता है। एक unit का एक नाम, स्टेटस, लॉग और रीस्टार्ट पॉलिसी होती है, जिसे अगला व्यक्ति बिना बताए ढूंढ सकता है।

nohup और setsid: इसे चलाएं और भूल जाएं

nohup ./import.sh > ~/import.log 2>&1 &
echo $! > ~/import.pid

nohup, SIGHUP के disposition को ignore पर सेट करता है और फिर आपकी कमांड चलाता है, जिससे kernel का hangup सिग्नल आने पर भी कुछ नहीं होता। redirect आपको स्वयं लिखना होता है। यदि आप standard output को terminal पर ही छोड़ देते हैं, तो nohup इसे आपके लिए current directory में nohup.out में redirect कर देता है, और यदि वह न बन पाए तो $HOME/nohup.out का उपयोग करता है, साथ ही यह संदेश प्रिंट करता है:

nohup: ignoring input and appending output to 'nohup.out'

उस फाइल को ट्रैक करना मुश्किल हो सकता है, इसलिए उसका नाम स्वयं रखें। $! में अंतिम background job का PID (process identifier) होता है, और इसे save करने का मतलब है कि आप दोबारा login करने के बाद job की स्थिति देख सकते हैं।

setsid इसी समस्या को दूसरे दृष्टिकोण से हल करता है। यह कमांड को एक नए session में चलाता है जिसका कोई controlling terminal नहीं होता, इसलिए ऐसा कोई terminal मौजूद ही नहीं होता जो इसे hang कर सके।

setsid --fork ./import.sh > ~/import.log 2>&1

--fork का उपयोग करें। इसके बिना, setsid हर बार setsid() को वहीं call कर देता है जहाँ process पहले से ही process group leader न हो, जो कि shell script के अंदर होता है, और फिर आपकी script वहीं रुक जाती है। --fork के साथ, script और prompt दोनों पर व्यवहार एक समान रहता है।

जांचें कि आपको वास्तव में क्या मिला:

ps -o pid,ppid,sid,tty,stat,cmd -p "$(cat ~/import.pid)"

TTY कॉलम में ? का मतलब है कि process का कोई controlling terminal नहीं है, इसलिए कोई भी चीज़ इसे hang नहीं कर सकती। nohup के अंतर्गत, TTY कॉलम तब तक pts/0 जैसा कुछ दिखाता है जब तक आप connected रहते हैं, और pty नष्ट होने के बाद यह ? हो जाता है। दोनों ही परिणाम सही हैं। job सुरक्षित है।

disown: पहले से शुरू किए गए जॉब को बचाना

आपने foreground में दो घंटे का जॉब शुरू किया और फिर आपको इस समस्या का ध्यान आया। इसे kill न करें और न ही दोबारा शुरू करें।

# press Ctrl-Z to suspend the job first
bg
jobs -l
disown -h %1

Ctrl-Z जॉब को suspend करता है, bg इसे background में resume करता है, और jobs -l इसके PID के बगल में इसका जॉब नंबर प्रिंट करता है। disown -h %1 उस जॉब को मार्क करता है ताकि bash उसे SIGHUP न भेजे। साधारण disown %1 जॉब को bash की टेबल से पूरी तरह हटा देता है, जिसका hangup पर वही प्रभाव पड़ता है, लेकिन फिर jobs इसे लिस्ट नहीं करता है।

disown जो नहीं कर सकता, वह है आउटपुट को मूव करना। प्रोसेस अभी भी pty को अपने standard output के रूप में रखता है, और जब pty हट जाता है तो अगला write EIO रिटर्न करता है। इसलिए disown एक शांत जॉब को तो सुरक्षित बचा लेता है, जैसे कि कोई compile जो फाइल में लिख रहा हो, लेकिन अक्सर यह ज्यादा आउटपुट देने वाले जॉब को खो देता है। जॉब या तो बिना कहीं प्रिंट किए जीवित रहता है, या आउटपुट की अगली लाइन पर मर जाता है।

फाइल डिस्क्रिप्टर के लिए एक रेस्क्यू टूल मौजूद है। reptyr एक चल रही प्रोसेस को आपके वर्तमान टर्मिनल पर ले आता है: इसे sudo apt install -y reptyr के साथ इंस्टॉल करें, फिर tmux विंडो के अंदर से reptyr <pid> चलाएं। यह ptrace के माध्यम से काम करता है, और Ubuntu में kernel.yama.ptrace_scope = 1 होता है, जो केवल आपके अपने descendants को trace करने की अनुमति देता है, इसलिए आपके द्वारा inherit की गई प्रोसेस के लिए sudo reptyr <pid> की आवश्यकता होती है। इसे एक आपातकालीन टूल के रूप में मानें। इस पर आधारित कोई रूटीन न बनाएं।

tmux: वह काम जिसे आपको मॉनिटर करना है और जिस पर वापस आना है

tmux (terminal multiplexer) इस समस्या का समाधान एक अलग स्तर पर करता है। यह आपके process को pty से बचाने के बजाय, उसे एक ऐसा pty देता है जो आपके SSH session का हिस्सा नहीं होता। tmux server उस session के बाहर चलता है और उसके अंदर चल रही हर चीज़ के terminal का स्वामी होता है। आपका SSH connection केवल उससे जुड़ा एक viewer मात्र है। connection कटने पर भी server को इसका पता नहीं चलता।

sudo apt update && sudo apt install -y tmux
tmux new -s import

उस window में अपना काम शुरू करें, फिर detach होने के लिए Ctrl-b दबाएं और उसके बाद d दबाएं। बाद में फिर से login करें और काम वहीं से उठाएं:

tmux ls
tmux attach -t import

tmux ls को import: 1 windows से शुरू होने वाली एक लाइन दिखानी चाहिए। यदि यह no server running on /tmp/tmux-1000/default दिखाता है, तो इसका मतलब है कि जुड़ने के लिए कोई session मौजूद नहीं है, क्योंकि या तो वह कभी बनाया ही नहीं गया था या किसी चीज़ ने server को बंद कर दिया है।

screen भी अलग keystroke के साथ वही काम करता है। screen -S import एक session बनाता है, और Ctrl-a के बाद d उससे detach हो जाता है। screen -ls मौजूद sessions की सूची दिखाता है और screen -r import किसी एक session पर वापस ले आता है। यहाँ दोनों में से कोई भी tool इस्तेमाल किया जा सकता है। detach करने वाली key ही वह हिस्सा है जिसे लोग अक्सर भूल जाते हैं।

एक multiplexer उन interactive कार्यों के लिए भी सही जगह है जिन्हें signal drop होने पर भी चलते रहना चाहिए। यही कारण है कि tmux के अंदर VPS पर Claude Code चलाना एक सामान्य setup है, और यही वह चीज़ है जो मोबाइल नेटवर्क पर सर्वर session को फोन से नियंत्रित करना संभव बनाती है, जहाँ connection हर कुछ मिनटों में फिर से जुड़ता रहता है।

systemd-run: कार्य को PID 1 को सौंपना

ऐसे कार्य के लिए जो आप पर बिल्कुल भी निर्भर नहीं होना चाहिए, उसे init system को सौंप दें।

sudo systemd-run --unit=bigsync --collect /usr/bin/rsync -aH --stats /srv/data/ /mnt/backup/

यह bigsync.service नामक एक transient service unit बनाता है। इसे अपना cgroup मिलता है, कोई controlling terminal नहीं होता, और आपके login से इसका कोई संबंध नहीं होता। कमांड तुरंत return हो जाती है और Running as unit: bigsync.service प्रिंट करती है। इसे इनमें से किसी एक के साथ देखें:

systemctl status bigsync
journalctl -u bigsync -f

--collect systemd को निर्देश देता है कि कार्य पूरा होने पर unit को हटा दे, भले ही वह विफल (fail) हो गया हो। इसके बिना, एक विफल transient unit loaded रहती है और उसका नाम व्यस्त (taken) रहता है, इसलिए अगली बार चलाने पर यह संदेश आता है कि unit पहले से मौजूद है। आउटपुट हर लाइन पर timestamps के साथ journal में जाता है। Journal entries केवल तभी reboot के बाद भी बनी रहती हैं जब /var/log/journal मौजूद हो, इसलिए यदि आप ऐसा चाहते हैं तो sudo mkdir -p /var/log/journal चलाएं और systemd-journald को restart करें।

एक सामान्य user के रूप में, बिना sudo के systemd-run को कॉल करने पर polkit से authorization मांगा जाता है और ==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units === प्रिंट होता है। System units के लिए sudo का उपयोग करें।

आप कार्य को अपने स्वयं के user manager के अंतर्गत भी चला सकते हैं:

systemd-run --user --unit=bigsync --collect /usr/bin/rsync -aH /srv/data/ /mnt/backup/

इसमें एक समस्या है। आपका per-user manager, user@1000.service, सामान्यतः आपके अंतिम session के समाप्त होने पर रुक जाता है, और यह अपने साथ हर user unit को भी बंद कर देता है। Lingering को एक बार चालू करें:

loginctl enable-linger "$USER"
loginctl show-user "$USER" --property=Linger

दूसरी कमांड को Linger=yes प्रिंट करना चाहिए। Lingering चालू होने पर, आपका user manager boot के समय शुरू होता है और आप logged in हों या न हों, चलता रहता है। इसके बिना, systemd-run --user आपको nohup की तुलना में कोई लाभ नहीं देता है।

systemd-run --scope एक अलग चीज है। यह कमांड को foreground में, आपके terminal से जुड़े हुए चलाता है, इसलिए यह यहाँ मदद नहीं करता है।

किसी भी ऐसी चीज के लिए जिसे आप एक से अधिक बार चलाएंगे, हर बार transient unit टाइप करने के बजाय unit को लिख लें।

जिस कार्य को आप दोबारा चलाएंगे उसके लिए एक permanent unit
[Unit]
Description=Nightly data sync
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=deploy
WorkingDirectory=/srv/data
ExecStart=/usr/local/bin/nightly-sync.sh

इसे /etc/systemd/system/nightly-sync.service के रूप में save करें, sudo systemctl daemon-reload चलाएं, फिर इसे sudo systemctl start nightly-sync के साथ start करें और journalctl -u nightly-sync के साथ इसे पढ़ें। जब इसे मांग (demand) के बजाय schedule पर चलना हो, तो एक संबंधित .timer फाइल जोड़ें।

systemd service unit और उसके timer को लिखना फाइल फॉर्मेट और schedule syntax को पूरी तरह से कवर करता है।

आउटपुट कहाँ जाता है, और यह गायब क्यों हो जाता है

रीडायरेक्शन का क्रम महत्वपूर्ण है। > file 2>&1 स्टैंडर्ड आउटपुट को फाइल की ओर निर्देशित करता है और फिर स्टैंडर्ड एरर को भी उसी स्थान पर भेजता है। 2>&1 > file इसे उल्टा करता है: स्टैंडर्ड एरर टर्मिनल पर जाना जारी रखता है, और टर्मिनल ही वह चीज है जो बंद होने वाली है। Bash दोनों स्ट्रीम्स के लिए एक साथ &> file को भी स्वीकार करता है।

दूसरी हैरानी बफरिंग की है। जब स्टैंडर्ड आउटपुट एक टर्मिनल होता है, तो C लाइब्रेरी हर लाइन को फ्लश करती है। जब स्टैंडर्ड आउटपुट एक फाइल होती है, तो यह कुछ किलोबाइट्स के ब्लॉक बफर पर स्विच हो जाती है, इसलिए tail -f ~/import.log मिनटों तक कुछ नहीं दिखाता और जॉब मृत प्रतीत होती है। लाइन बफरिंग को मजबूर करने के लिए stdbuf -oL ./import.sh > ~/import.log 2>&1 का उपयोग करें, या प्रोग्राम के अपने स्विच का उपयोग करें, जैसे कि python3 -u या grep --line-buffered

इस पैटर्न से बचें:

nohup ./import.sh 2>&1 | tee ~/import.log &

nohup केवल import.sh को सुरक्षित करता है और किसी अन्य को नहीं। tee उसी पाइपलाइन में एक अलग प्रोसेस है, और यह अभी भी हैंगअप पर समाप्त हो जाती है। import.sh तब बिना रीडर वाली पाइप में लिख रहा होता है, इसलिए यह SIGPIPE प्राप्त करता है और रुक जाता है। पूरी पाइपलाइन को setsid bash -c '...' के अंदर रखें, या सीधे फाइल में लिखें और दोबारा कनेक्ट होने पर उस पर tail -f चलाएं।

विशेष रूप से rsync के लिए एक और विवरण। --info=progress2 कैरिज रिटर्न की एक स्ट्रीम लिखता है जो टर्मिनल पर सही दिखती है और लॉग फाइल या जर्नल में एक विशाल लाइन बन जाती है। अनअटेंडेड रन के लिए, इसे हटा दें और इसके बजाय --stats का उपयोग करें।

जब कोई जॉब आपके शेल में काम करती है लेकिन systemd या cron के तहत विफल हो जाती है

आपका इंटरैक्टिव शेल /etc/profile, ~/.profile और ~/.bashrc को पढ़ता है, इसलिए इसमें आपका PATH, आपके वर्ज़न मैनेजर शिम्स (shims) और आपके एक्सपोर्ट किए गए वेरिएबल्स मौजूद होते हैं। एक systemd यूनिट इनमें से कुछ भी नहीं पढ़ती है। Cron भी इनमें से कुछ नहीं पढ़ता है: Debian और Ubuntu पर, cron जॉब्स को SHELL=/bin/sh और PATH=/usr/bin:/bin के साथ चलाता है।

systemd के तहत इसका लक्षण यह है कि systemctl status में (code=exited, status=203/EXEC) रिपोर्ट होता है, जिसका अर्थ है कि systemd उस फाइल को बिल्कुल भी निष्पादित (execute) नहीं कर सका, क्योंकि पाथ गलत था या फाइल को एक्जीक्यूटेबल के रूप में मार्क नहीं किया गया था। Cron के तहत यह आमतौर पर command not found होता है, जो लोकल मेल द्वारा डिलीवर किया जाता है, या यदि कोई मेल सिस्टम इंस्टॉल नहीं है तो कहीं भी डिलीवर नहीं होता है।

अनुमान लगाने में एक घंटा बर्बाद करने से पहले यह जांच लें कि एनवायरनमेंट क्या है:

sudo systemd-run --collect --wait --unit=envtest /usr/bin/env
journalctl -u envtest --no-pager

यह उस सटीक एनवायरनमेंट को प्रिंट करता है जिसके साथ आपकी जॉब चलेगी। फिर उस अंतर को ठीक करें। अपनी किसी भी चीज के लिए एब्सोल्यूट पाथ (absolute paths) का उपयोग करें, क्योंकि systemd एक साधारण rsync को फिक्स्ड सिस्टम पाथ लिस्ट के आधार पर रिजॉल्व करता है, न कि आपके शेल के PATH के आधार पर। जिन वेरिएबल्स की आपको आवश्यकता है उन्हें कमांड लाइन पर -p Environment="KEY=value" के साथ, या यूनिट फाइल में EnvironmentFile=/etc/default/myjob के साथ पास करें। जब किसी जॉब को वास्तव में आपके लॉगिन एनवायरनमेंट की आवश्यकता हो, तो उसे /bin/bash -lc 'my-command' के रूप में चलाएं और यह स्वीकार करें कि जॉब अब आपकी डॉटफाइल्स (dotfiles) पर निर्भर है।

डिटैच्ड जॉब को अभी भी क्या समाप्त कर सकता है

  • एक रीबूट। रीबूट के बाद tmux का कुछ भी सुरक्षित नहीं रहता, क्योंकि सर्वर एक सामान्य प्रोसेस है और सेशन इसकी इन-मेमोरी स्थिति में होते हैं। कर्नेल अपडेट के लिए रीबूट की आवश्यकता होती है, इसलिए जिस जॉब को आप आसानी से रीस्टार्ट नहीं कर सकते, उसे एक यूनिट में होना चाहिए जिसे आप systemctl enable कर सकें।
  • आउट-ऑफ-मेमोरी किलर। dmesg -T | grep -i 'killed process' इसे दिखाता है, जिसमें उस प्रोसेस का नाम भी शामिल है जिसे उसने चुना है। एक छोटे VPS पर बड़ा इम्पोर्ट अक्सर इसका लक्ष्य बनता है।
  • logind क्लीनअप। यदि /etc/systemd/logind.conf में KillUserProcesses=yes सेट है, तो आपका अंतिम सेशन समाप्त होते ही आपकी बची हुई प्रोसेसेस समाप्त कर दी जाती हैं, और इसमें tmux सर्वर भी शामिल है। loginctl show --property=KillUserProcesses के साथ वर्तमान सेटिंग की जाँच करें, और loginctl enable-linger "$USER" के साथ अपने यूजर को छूट दें।
  • डिस्क का भर जाना। जॉब इसलिए रुक जाती है क्योंकि जिस लॉग को आपने रीडायरेक्ट किया था उसने फाइलसिस्टम को भर दिया है, न कि इसलिए कि आप लॉग आउट हो गए। सिग्नल को दोष देने से पहले df -h चलाएँ।

SSH के माध्यम से कनेक्टेड रहे बिना जॉब शुरू करना

ssh vps 'sudo systemd-run --unit=import --collect /usr/local/bin/import.sh'

systemd-run यूनिट के शुरू होते ही वापस आ जाता है, इसलिए ssh कमांड भी वापस आ जाती है, और जॉब का उस सेशन से कोई संबंध नहीं रहता जिसने इसे लॉन्च किया था। यह साफ-सुथरा तरीका है।

nohup संस्करण में अधिक सावधानी की आवश्यकता होती है:

ssh vps 'nohup ./import.sh > ~/import.log 2>&1 < /dev/null &'

रीडायरेक्शन के बिना, यह हैंग होता हुआ प्रतीत होता है। sshd चैनल को तब तक खुला रखता है जब तक किसी प्रोसेस के पास रिमोट कमांड का स्टैंडर्ड आउटपुट या स्टैंडर्ड एरर रहता है, और बैकग्राउंड में चल रही जॉब दोनों को इनहेरिट करती है। केवल nohup इसे ठीक नहीं करता है, क्योंकि nohup आउटपुट को केवल तब रीडायरेक्ट करता है जब वह आउटपुट एक टर्मिनल हो, और यहाँ यह आपके क्लाइंट के लिए एक पाइप है। < /dev/null जोड़ने से इनपुट साइड भी बंद हो जाती है। ssh -n क्लाइंट एंड से वही काम करता है।

FAQ

SSH connection टूटने पर मेरी command क्यों रुक जाती है?

आपका session जिस pty (pseudo-terminal) का उपयोग कर रहा था, वह नष्ट हो जाता है और kernel उस terminal पर मौजूद foreground process group को SIGHUP भेजता है। SIGHUP की डिफ़ॉल्ट क्रिया process को समाप्त करना है। Background jobs भी बंद हो जाती हैं, क्योंकि bash बाहर निकलने से पहले अपनी table में मौजूद हर job को SIGHUP भेजता है। जो command SIGHUP को ignore करती है, जैसे कि nohup के साथ शुरू की गई command, या जो कभी आपके session का हिस्सा ही नहीं थी, जैसे कि systemd unit, उस पर इसका कोई प्रभाव नहीं पड़ता।

छह घंटे चलने वाले rsync के लिए tmux बेहतर है या systemd-run?

systemd-run। एक tmux session आपके द्वारा शुरू की गई server process पर निर्भर करता है, इसलिए यह अगले reboot पर समाप्त हो जाता है और जो व्यक्ति tmux ls चलाना नहीं जानता, उसके लिए यह अदृश्य रहता है। sudo systemd-run --unit=bigsync --collect /usr/bin/rsync -aH --stats /srv/data/ /mnt/backup/ चलाने से आपको state के लिए systemctl status bigsync और output के लिए journalctl -u bigsync मिलता है, जिसे अगला administrator बिना बताए भी ढूँढ सकता है। tmux का उपयोग उन कार्यों के लिए करें जहाँ आपको screen देखने और उसमें type करने की आवश्यकता हो।

मैं उस job का output कैसे देखूँ जिसे मैंने redirect करना भुला दिया था?

आमतौर पर आप ऐसा नहीं कर सकते, क्योंकि वह output उस terminal पर गया जो अब मौजूद नहीं है। जब तक process चल रही है, आप sudo ls -l /proc/<pid>/fd के साथ उसकी open files की जाँच कर सकते हैं या sudo strace -p <pid> के साथ उसके system calls देख सकते हैं, लेकिन जो text पहले ही लिखा जा चुका है, वह जा चुका है। reptyr <pid> process को एक नए terminal पर ले जा सकता है, और Ubuntu के kernel.yama.ptrace_scope = 1 का मतलब है कि इसके लिए sudo की आवश्यकता होती है यदि process आपकी अपनी child नहीं है। इस समस्या से बचने की आदत यह है कि शुरुआत में ही output को एक file में redirect करें और उस file को tail -f करें।

क्या detached tmux session reboot के बाद भी बना रहता है?

नहीं। tmux server एक सामान्य process है और sessions उसकी in-memory state हैं, इसलिए reboot दोनों को समाप्त कर देता है। जब /etc/systemd/logind.conf, KillUserProcesses=yes को set करता है और आप अपने अंतिम session से log out करते हैं, तब भी यह समाप्त हो जाता है, जिसे loginctl enable-linger "$USER" रोकता है। ऐसे काम के लिए जिसे reboot के बाद अपने आप वापस आना है, एक systemd unit लिखें और उसे systemctl enable करें।

मेरी script shell में क्यों चलती है लेकिन systemd unit के रूप में विफल हो जाती है?

एक unit, /etc/profile या ~/.bashrc को नहीं पढ़ती है, इसलिए इसमें न तो आपके PATH additions होते हैं और न ही आपके exported variables। systemctl status में (code=exited, status=203/EXEC) दिखने का मतलब है कि systemd उस file को execute ही नहीं कर सका, इसलिए absolute path का उपयोग करें और executable bit की जाँच करें। sudo systemd-run --collect --wait --unit=envtest /usr/bin/env चलाएँ, उसे journalctl -u envtest के साथ पढ़ें, और आपको वह सटीक environment मिल जाएगा जो आपकी job को मिलता है। जो भी कमी हो, उसे Environment= या EnvironmentFile= के साथ पूरा करें।

#SSH#tmux#nohup#systemd#long-running-jobs