7 मिनट पढ़ें

क्या SSH पाइपलाइन का एग्जिट स्टेटस विफल कमांड छिपा सकता है?

SSH पाइपलाइन का exit status रिमोट कमांड की विफलता छिपा सकता है। Bash PIPESTATUS कैप्चर करें, pipefail संभालें और agents को ईमानदार परिणाम लौटाएं।

क्या SSH पाइपलाइन का एग्जिट स्टेटस विफल कमांड छिपा सकता है?

रिमोट कमांड विफल हो सकती है, फॉर्मेटर भरोसेमंद दिखने वाला आउटपुट लिख सकता है और एजेंट फिर भी सफलता की घोषणा कर सकता है। यह SSH का कोई रहस्य नहीं है। यह सामान्य shell semantics हैं, जो पर्याप्त सबूत के बिना नेटवर्क सीमा पार कर रही हैं।

समाधान केवल हर स्क्रिप्ट में set -o pipefail जोड़ देना नहीं है। pipefail एक संयुक्त परिणाम बदलता है। महत्वपूर्ण SSH काम चलाने वाले एजेंट को हर पाइपलाइन स्टेज का स्टेटस, अपेक्षित nonzero एग्जिट के लिए स्पष्ट नियम और ऐसा अंतिम रिमोट एग्जिट कोड चाहिए जिसे सफलता न समझा जा सके। Vector को तुरंत कॉपी करें, उसका नाम रखें और wrapper को तय करने दें कि सफलता का अर्थ क्या है।

हरी आखिरी कमांड पहली विफल कमांड छिपा सकती है

डिफॉल्ट रूप से shell पाइपलाइन आखिरी कमांड का एग्जिट स्टेटस लौटाती है। इसलिए deployment, migration, backup और repair के काम में यह पंक्ति खतरनाक है:

build_manifest | sign_manifest | tee /var/tmp/manifest.json

मान लें build_manifest इसलिए विफल हुई क्योंकि वह ज़रूरी फ़ाइल पढ़ नहीं सकी। sign_manifest को उपयोगी इनपुट न मिले और वह भी विफल हो सकती है, या खाली परिणाम बना सकती है। tee फिर भी फ़ाइल बना सकता है, शून्य बाइट लिख सकता है और शून्य स्टेटस के साथ समाप्त हो सकता है। Shell पूरी पाइपलाइन के लिए शून्य रिपोर्ट करता है। केवल $? जांचने वाले caller को सफलता दिखती है।

GNU Bash Reference Manual इसे साफ़ तौर पर बताता है: pipefail चालू न हो तो पाइपलाइन आखिरी कमांड का एग्जिट स्टेटस इस्तेमाल करती है। Bash synchronous pipeline की सभी कमांड का इंतज़ार करता है, लेकिन इंतज़ार करना उनके परिणाम सुरक्षित रखने के बराबर नहीं है।

इंटरैक्टिव टर्मिनल पर बैठा इंसान कभी-कभी गायब डेटा या error message देख लेता है। एजेंट का नज़रिया अक्सर सीमित होता है। उसे अधूरा transcript, formatted summary या केवल कमांड का अंतिम परिणाम मिल सकता है। अगर स्क्रिप्ट शून्य कहती है, तो एजेंट के पास कार्रवाई को सफल बताने का आधार होता है, भले ही मांगा गया काम हुआ ही न हो।

टीमें जिस अंतर को अक्सर मिला देती हैं, वह सरल है:

  • पाइपलाइन का exit status एक निर्णय मान है।
  • उसकी कमांड के statuses उस निर्णय के पीछे का सबूत हैं।

आपको दोनों चाहिए। निर्णय मान तय करता है कि रिमोट कमांड सफलता लौटाएगी या नहीं। सबूत reviewer, log या supervising agent को बताता है कि गलती कहां हुई।

यह सबसे महत्वपूर्ण तब होता है जब पहली स्टेज दुनिया में बदलाव करती है। मान लें रिमोट export production data पढ़ता है, उसे compress और encrypt करता है, फिर upload करता है। Upload client खाली stream भेजने के बाद भी शून्य पर समाप्त हो सकता है। Transcript में completed जैसे भरोसा देने वाले शब्द हो सकते हैं, क्योंकि बाद वाले प्रोग्राम ने अपना सीमित काम पूरा किया। यह परिणाम export के सफल होने का झूठा बयान नहीं बनना चाहिए।

SSH वही लौटाता है जो रिमोट shell लौटाना चुनता है

OpenSSH रिमोट shell pipeline के अंदर की कमांड की जांच नहीं करता। वह रिमोट कमांड का स्टेटस लौटाता है, या तब 255 लौटाता है जब SSH को खुद कोई त्रुटि मिले।

यह व्यवहार सही और उपयोगी है। SSH यह नहीं जान सकता कि रिमोट टेक्स्ट pipeline है, shell function है, script है या ऐसा application है जो exit codes को अपने तरीके से इस्तेमाल करता है:

ssh deploy@host 'generate | transform | tee result.txt'

रिमोट login shell उस कमांड को parse करता है। अगर उसकी pipeline semantics आखिरी tee का स्टेटस रिपोर्ट करती हैं, तो SSH वही स्टेटस स्थानीय मशीन को लौटाएगा। रिमोट shell द्वारा पुराने परिणाम छोड़ दिए जाने के बाद स्थानीय caller उन्हें दोबारा नहीं बना सकता।

स्थानीय shell में set -o pipefail लगाने से रिमोट pipeline ठीक नहीं होती। यह कमांड केवल स्थानीय pipeline के status rules बदलती है:

set -o pipefail
ssh deploy@host 'generate | transform | tee result.txt'

generate | transform | tee result.txt का मालिक अब भी रिमोट shell है। उसे अपना स्पष्ट shell और अपनी failure handling चाहिए।

एक दूसरा जाल भी है। यह स्थानीय कमांड SSH के लौटने के बाद एक और pipeline बनाती है:

ssh deploy@host 'remote command' 2>&1 | tee session.log

अब दो अलग pipelines हैं:

  1. remote command के भीतर रिमोट shell की pipeline हो सकती है।
  2. स्थानीय shell में ssh | tee session.log pipeline है।

सफल स्थानीय tee, SSH transport failure या रिमोट wrapper के nonzero exit को छिपा सकता है। आपको host पर रिमोट pipeline और SSH के आसपास की स्थानीय pipeline दोनों जांचनी होंगी। इस पूरी पंक्ति को एक opaque command मानना false green results के review से बच निकलने का तरीका है।

Pipefail विफलता पकड़ता है, लेकिन उसका कारण नहीं बताता

set -o pipefail Bash का संयुक्त परिणाम बदलता है। इसके चालू होने पर Bash उस सबसे दाईं ओर वाली कमांड का स्टेटस लौटाता है जो nonzero पर समाप्त हुई, या सभी कमांड सफल होने पर शून्य लौटाता है।

कई स्क्रिप्ट के लिए यह वास्तविक सुधार है:

set -o pipefail
produce_data | validate_data | publish_data
printf 'pipeline status: %s\n' "$?"

अगर produce_data 17 पर समाप्त हो और बाद की कमांड शून्य लौटाएं, तो pipeline 17 लौटाएगी। अगर validate_data 4 लौटाए और publish_data शून्य लौटाए, तो pipeline 4 लौटाएगी। Calling process को झूठ के बजाय failure मिलता है।

लेकिन एक से अधिक स्टेज विफल होने पर pipefail विवरण खो देता है। मान लें statuses 17 4 0 हैं। Pipeline result 4 होगा, क्योंकि 4 दाईं ओर वाली विफल कमांड से आया है। इससे पता चलता है कि विफलता हुई, लेकिन यह नहीं पता चलता कि validator ने producer की विफलता पैदा की, उस पर प्रतिक्रिया दी या स्वतंत्र रूप से विफल हुआ।

इसीलिए pipefail एक guardrail है, report format नहीं। जब आप पूरी pipeline को एक इकाई की तरह विफल करना चाहते हैं तब इसका इस्तेमाल करें। जब आपको बाद में इन सवालों का जवाब देना हो, तब PIPESTATUS इस्तेमाल करें:

  • किस स्टेज ने nonzero code लौटाया?
  • क्या पहली स्टेज विफल होने के बाद अगली स्टेज चली और सफल हुई?
  • क्या process ने अपना error लौटाने के बजाय signal प्राप्त किया?
  • क्या इस खास कमांड के लिए nonzero code अपेक्षित है?

इस अंतर को || true से न छिपाएं:

produce_data | validate_data | publish_data || true

यह तरीका लोकप्रिय है क्योंकि इससे स्क्रिप्ट चलती रहती है। साथ ही यह caller के पास मौजूद एकमात्र signal भी मिटा देता है। अगर किसी स्टेज का nonzero लौटाना वैध हो सकता है, तो actual vector कॉपी करने के बाद उस स्टेज के लिए स्वीकार्य status लिखें। पूरी pipeline की failure को माफ़ न करें।

अगर एक कमांड भी पहले चला दी तो PIPESTATUS गायब हो जाता है

Bash हर स्टेज का exit code PIPESTATUS array में देता है। यह array जानबूझकर fragile है: इसमें सबसे हाल में चली foreground pipeline का विवरण होता है और अगली कमांड इसे बदल सकती है।

यह ठीक दिखता है, लेकिन गलत है:

source_data | normalize | upload
pipeline_rc=$?
printf 'pipeline result: %s\n' "$pipeline_rc"
statuses=("${PIPESTATUS[@]}")

अंतिम assignment तक पहुंचने से पहले pipeline_rc=$? assignment और printf चल चुके हैं। PIPESTATUS अब source_data | normalize | upload का विवरण नहीं रखता।

Array को सबसे पहले कॉपी करें:

source_data | normalize | upload
statuses=("${PIPESTATUS[@]}")

फिर pipeline के संयुक्त code पर निर्भर हुए बिना इसे जांचें:

printf 'source_data=%s normalize=%s upload=%s\n' \\
  "${statuses[0]}" "${statuses[1]}" "${statuses[2]}"

इसी कारण सामान्य set -e diagnosis को और कठिन बना सकता है। pipefail चालू होने पर विफल pipeline Bash को अगली पंक्ति में PIPESTATUS कॉपी करने से पहले exit करा सकती है। Shell error handling में कई संदर्भ-आधारित अपवाद हैं और केवल set -e पर निर्भर स्क्रिप्ट अक्सर command failure के ठीक समय कम सबूत देती हैं।

जिस pipeline के statuses महत्वपूर्ण हों, उसे चलाने और snapshot लेने के लिए जरूरी कुछ पंक्तियों में errexit बंद करें। फिर स्पष्ट निर्णय लें। यह magic shell option से अधिक code है, लेकिन incident के समय इसे पढ़ा जा सकता है।

रिमोट प्रोग्राम को आवश्यक shell के तहत चलाएं

हर रिमोट कॉल की जांच करें
Activity जर्नल में हर कॉल देखें, किसी आखिरी सफलता संदेश पर निर्भर न रहें।

PIPESTATUS Bash array है। यह portable POSIX sh syntax नहीं है और POSIX shell में pipefail आवश्यक नहीं है। SSH के जरिए चलाया गया रिमोट command ऐसे login shell में चल सकता है जिसे आपने चुना ही नहीं। किसी host पर Bash हो सकता है, दूसरे पर dash, zsh या restricted shell।

अनिर्दिष्ट रिमोट shell को Bash syntax न भेजें और यह उम्मीद न करें कि मशीन आपकी बात मानेगी। Bash को स्पष्ट रूप से शुरू करें:

ssh deploy@host 'bash -s' <<'REMOTE_SCRIPT'
printf 'alpha\n' | grep 'beta' | tee /var/tmp/example.out
statuses=("${PIPESTATUS[@]}")
printf 'stages=%s,%s,%s\n' \\
  "${statuses[0]}" "${statuses[1]}" "${statuses[2]}" >&2
REMOTE_SCRIPT

Quoted heredoc delimiter महत्वपूर्ण है। <<'REMOTE_SCRIPT' स्थानीय shell को variables, command substitutions और backslashes expand करने से रोकता है, इससे पहले कि वह script भेजे। रिमोट Bash process को वही text मिलता है जो आपने लिखा।

macOS पर system Bash पुराना है, लेकिन वह indexed arrays, PIPESTATUS और set -o pipefail सपोर्ट करता है। इसका मतलब यह नहीं कि /bin/sh Bash है। #!/bin/bash तभी मदद करता है जब आप file को सीधे चलाते हैं। अगर आप ssh host '...' को one-line command देते हैं, तो remote login shell उसे parse करेगा, जब तक आप स्पष्ट रूप से Bash शुरू न करें।

नियमित automation path के लिए रिमोट wrapper को versioned script में रखें और उसका absolute path चलाएं। थोड़े समय के agent work के लिए quoted heredoc के साथ bash -s की जांच आसान होती है, क्योंकि पूरा remote program स्थानीय action request में दिखाई देता है।

Wrapper को stages का नाम देना और ईमानदार परिणाम लौटाना चाहिए

एक उपयोगी remote wrapper चार काम करता है। वह pipeline चलाता है, status vector तुरंत कॉपी करता है, machine-readable record लिखता है और आवश्यक stage विफल होने पर nonzero exit करता है।

यह उदाहरण तीन-stage data transfer इस्तेमाल करता है। Commands बदलें, लेकिन control flow बनाए रखें। यह जानबूझकर pipeline के बाद का निर्णय लेने के लिए set -e पर निर्भर नहीं करता।

#!/usr/bin/env bash
set -uo pipefail

run_export() {
  local -a status
  local stage
  local -a names=("collect" "compress" "send")

  set +e
  collect_records | gzip -c | send_archive --destination daily
  status=("${PIPESTATUS[@]}")
  set -e

  if ((${#status[@]} != ${#names[@]})); then
    printf 'agent_pipeline_error pipeline=export reason=status_count expected=%s got=%s\n' \\
      "${#names[@]}" "${#status[@]}" >&2
    return 70
  fi

  for stage in "${!names[@]}"; do
    printf 'agent_pipeline_status pipeline=export stage=%s code=%s\n' \\
      "${names[$stage]}" "${status[$stage]}" >&2
  done

  for stage in "${!status[@]}"; do
    if (( status[stage] != 0 )); then
      printf 'agent_pipeline_result pipeline=export outcome=failed\n' >&2
      return "${status[$stage]}"
    fi
  done

  printf 'agent_pipeline_result pipeline=export outcome=ok\n' >&2
  return 0
}

run_export

सफल compressor और sender के साथ failed collection इस तरह का output देती है:

agent_pipeline_status pipeline=export stage=collect code=23
agent_pipeline_status pipeline=export stage=compress code=0
agent_pipeline_status pipeline=export stage=send code=0
agent_pipeline_result pipeline=export outcome=failed

Wrapper 23 पर exit करता है। SSH स्थानीय process को 23 लौटाता है। Agent बता सकता है कि export collect पर विफल हुआ, भले ही send_archive ने empty stream के लिए completion message लिखा हो।

लौटाए गए code से अधिक महत्वपूर्ण उसके पीछे का अनुशासन है। इस wrapper में pipeline order के अनुसार पहला nonzero status चुना जाता है। Bash pipefail इसके बजाय दाईं ओर वाला nonzero status चुनता है। दोनों policies काम कर सकती हैं, अगर आप उन्हें स्पष्ट करें और test करें। Operations work में मुझे पहला failed stage अधिक उपयोगी लगता है, क्योंकि वह आम तौर पर शुरुआती fault के करीब होता है। पूरा status vector action record में रखें, ताकि किसी को एक संख्या से अनुमान न लगाना पड़े।

Stage names केवल सजावट नहीं हैं। 0=23,1=0,2=0 देखने पर व्यक्ति को script फिर से खोलनी पड़ती है। collect=23,compress=0,send=0 supervisor को failure route करने, context जोड़ने या retry सुरक्षित है या नहीं तय करने देता है।

स्थानीय logging दूसरा false success बना सकती है

क्रेडेंशियल नहीं, नतीजे लौटाएं
एजेंट को कमांड के नतीजे मिलें, जबकि कनेक्शन बनाने के लिए इस्तेमाल क्रेडेंशियल Sallyport के पास रहे।

Operators को स्थानीय transcript चाहिए। Agents को भी चाहिए। इसे पाने का सामान्य तरीका यह है:

ssh deploy@host 'bash -s' < remote-export.sh 2>&1 | tee ssh-export.log

अगर SSH 23 लौटाता है, लेकिन स्थानीय tee transcript लिखकर शून्य लौटाती है, तो default रूप से स्थानीय pipeline शून्य लौटाती है। आपने रिमोट झूठ ठीक किया और स्थानीय झूठ बना दिया।

स्थानीय statuses भी कॉपी करें:

set +e
ssh deploy@host 'bash -s' < remote-export.sh 2>&1 | tee ssh-export.log
local_status=("${PIPESTATUS[@]}")
set -e

ssh_rc=${local_status[0]}
tee_rc=${local_status[1]}
printf 'ssh=%s tee=%s\n' "$ssh_rc" "$tee_rc" >&2

if (( ssh_rc != 0 )); then
  exit "$ssh_rc"
fi
if (( tee_rc != 0 )); then
  exit "$tee_rc"
fi

सिर्फ स्थानीय pipefail चालू करके रुक न जाएं। इससे ssh या tee में से कोई भी विफल होने पर nonzero aggregate result मिलता है, जो default behavior से बेहतर है। लेकिन यह agent को नहीं बता सकता कि remote action विफल हुआ, network connection विफल हुआ या local logging विफल हुई। इन मामलों में अलग निर्णय लेने पड़ते हैं।

SSH status 255 को अलग तरह से संभालें। OpenSSH इसे remote command result के बजाय SSH client path की त्रुटि के लिए सुरक्षित रखता है। Wrapper को इसे transport या SSH execution failure के रूप में रिपोर्ट करना चाहिए, यह दावा नहीं करना चाहिए कि किसी नामित remote pipeline stage ने 255 लौटाया।

स्थानीय और रिमोट results अलग रखने का एक और व्यावहारिक कारण है। Transcript में कई remote pipeline records, login shell की warnings और SSH diagnostic हो सकते हैं। अगर agent free-form text में दिखाई देने वाली आखिरी संख्या पढ़ेगा, तो कभी न कभी गलत संख्या चुन लेगा। पहचानने योग्य records इस्तेमाल करें और final action result को वास्तविक process exit status से जोड़ें।

SIGPIPE के लिए लिखित अपवाद चाहिए, blanket pardon नहीं

pipefail ऐसी विफलता सामने लाता है जिसे कई scripts पहले अनदेखा करती थीं: SIGPIPE। Bash में signal number N से समाप्त process को 128 + N status मिलता है। SIGPIPE अक्सर 141 के रूप में दिखता है।

जानबूझकर होने वाला सामान्य मामला है:

generate_many_lines | head -n 10

head दस lines पढ़कर सफलतापूर्वक समाप्त हो जाता है। Generator लिखना जारी रख सकता है, reader न बचने पर SIGPIPE पा सकता है और 141 पर समाप्त हो सकता है। pipefail के साथ pipeline विफल दिख सकती है, भले ही मांगा गया दस-line sample तैयार हो गया हो।

इसका अर्थ यह नहीं कि हर pipeline में 141 harmless है। Network client, compressor या data producer को SIGPIPE इसलिए मिल सकता है कि अप्रत्याशित downstream consumer crash हो गया या input अस्वीकार कर दिया। हर 141 को सफलता मानने से टूटा हुआ transfer छिप जाएगा।

सही नियम सीमित है: signal-derived status को तभी स्वीकार करें जब उस stage का जल्दी रुकना command के intended contract का हिस्सा हो। यह अपवाद global shell setting में नहीं, उसी stage के पास लिखें।

उदाहरण के लिए, जानबूझकर बनाए गए preview का wrapper generate_many_lines=141 तभी स्वीकार कर सकता है जब head=0 हो:

if (( status[0] == 141 && status[1] == 0 )); then
  printf 'agent_pipeline_result pipeline=preview outcome=ok reason=expected_sigpipe\n' >&2
  return 0
fi

हर दूसरा nonzero result failure ही रहेगा। यह छोटी-सी specificity एक आम overcorrection रोकती है: लोग pipefail चालू करते हैं, एक बार noisy 141 देखते हैं और फिर पूरे automation estate में इसे बंद कर देते हैं।

Agent को command output से अलग सबूत चाहिए

संवेदनशील SSH कुंजियों को सुरक्षित रखें
जब भी किसी खास SSH कुंजी का इस्तेमाल हो, वन-क्लिक या Touch ID मंजूरी ज़रूरी बनाएं।

Agent को prose पढ़कर success तय नहीं करनी चाहिए। Commands विफल होने से पहले success words लिख सकती हैं, tools warnings को results के साथ मिला सकते हैं और एक stage गलत हो जाने के बाद remote script final line लिख सकती है।

Action contract को दो layers में बांटें:

  1. Process exit code तय करे कि requested action सफल हुआ या नहीं।
  2. Structured status records हर महत्वपूर्ण pipeline stage का विवरण दें।

सामान्य command output debugging के लिए उपलब्ध रखें, लेकिन agent से control flow अनुमान लगाने को न कहें। ऊपर वाले wrapper में stderr पर agent_pipeline_status और agent_pipeline_result से शुरू होने वाले records जाते हैं। Calling program उस stream को सुरक्षित रख सकता है, केवल इन exact records को parse कर सकता है और बाकी output इंसान को दिखा सकता है।

Untrusted command output में दिखाई देने वाले marker पर केवल इसलिए भरोसा न करें कि वह status record जैसा दिखता है। अगर pipeline stage किसी दूसरे user या system से मिले data को संभालती है, तो उस data में आपके record जैसी line हो सकती है। बेहतर तरीका है कि wrapper stage output capture करे और pipeline खत्म होने के बाद खुद records लिखे। अधिक जोखिम वाले काम में restrictive permissions वाली dedicated result file इस्तेमाल करें, फिर final record लिखने से पहले wrapper उसे पढ़कर validate करे।

Agent की report में remote exit code, local SSH exit code और उपलब्ध होने पर नामित remote stage statuses शामिल होने चाहिए। इन परिणामों में भी अंतर स्पष्ट होना चाहिए:

  • remote action चला और किसी नामित stage पर विफल हुआ;
  • remote wrapper पूरा status record नहीं बना सका;
  • SSH action channel स्थापित या कायम नहीं रख सका;
  • remote action पूरा होने के बाद local transcript capture विफल हुई।

ये operational रूप से अलग तथ्य हैं। Network loss के बाद retry करने से पूरा हो चुका remote mutation दोबारा हो सकता है। Failed validation stage के बाद retry सुरक्षित हो सकता है। Local tee विफल होने के बाद retry बेकार हो सकता है, क्योंकि remote work पहले ही हो चुका है।

Sallyport agent से SSH credential दूर रखते हुए SSH action चला सकता है, लेकिन remote command को अब भी यह ईमानदार exit और evidence contract चाहिए।

Agent तक पहुंचने से पहले failure paths test करें

Shell wrapper भरोसा तभी कमाता है जब वह नियंत्रित तरीकों से विफल हो। Happy path test करना सबसे कम महत्वपूर्ण branch साबित करता है।

ऐसी disposable commands बनाएं जो आपके देखने लायक statuses लौटाएं:

fail_23() { printf 'collector failed\n' >&2; return 23; }
pass_through() { cat; }
succeed() { cat >/dev/null; return 0; }

set +e
fail_23 | pass_through | succeed
status=("${PIPESTATUS[@]}")
set -e
printf 'observed=%s,%s,%s\n' "${status[0]}" "${status[1]}" "${status[2]}"

अपेक्षित परिणाम 23,0,0 है। फिर यही pattern उस exact SSH invocation से चलाएं जिसे agent इस्तेमाल करता है। केवल local shell test पर न रुकें, क्योंकि remote shell selection, heredoc quoting, local transcript pipeline और wrapper exit behavior पहली जांच के बाहर होते हैं।

कम से कम इन मामलों को test करें:

  • हर stage सफल हो और wrapper zero पर exit करे;
  • शुरुआती stage विफल हो, जबकि बाद की stages zero लौटाएं;
  • कुछ input consume करने के बाद बीच वाली stage विफल हो;
  • SSH connect या authenticate न कर सके;
  • local tee transcript न लिख सके;
  • जानबूझकर बनाई गई head pipeline अपेक्षित SIGPIPE rule को trigger करे।

हर मामले के लिए expected exit code और expected stage records लिखें। अगर test पहली stage के nonzero लौटाने के बाद success बताता है, तो wrapper अपना काम नहीं कर रहा।

आसान shortcut यह है कि agent हर action के बाद transcript देखे और तय करे कि output सही दिखता है या नहीं। यह load में विफल होगा, tools की wording बदलने पर विफल होगा और output truncate होने पर भी विफल होगा। Exit codes control channel हैं। Stage records evidence channel हैं। दोनों को अलग रखें, SSH के पार दोनों सुरक्षित रखें और किसी final tee को यह तय न करने दें कि remote action हुआ था या नहीं।

सामान्य प्रश्न

क्या SSH रिमोट पाइपलाइन की हर कमांड का एग्जिट कोड लौटाता है?

नहीं। OpenSSH रिमोट कमांड का एग्जिट स्टेटस लौटाता है, लेकिन रिमोट शेल पाइपलाइन आम तौर पर आखिरी स्टेज का स्टेटस रिपोर्ट करती है। अगर वह स्टेज tee, cat या कोई ऐसा फॉर्मेटर है जो शून्य पर समाप्त होता है, तो पहले की कमांड विफल होने पर भी SSH सही रूप से शून्य लौटा सकता है।

क्या SSH ऑटोमेशन के लिए pipefail पर्याप्त है?

set -o pipefail पाइपलाइन का परिणाम आखिरी स्टेज के स्टेटस से बदलकर दाईं ओर वाली ऐसी स्टेज का स्टेटस कर देता है जो शून्य नहीं है। इससे कॉल करने वाले को पता चलता है कि कुछ विफल हुआ, लेकिन यह हर विफल स्टेज की पहचान नहीं करता और एजेंट के लिए स्टेज-दर-स्टेज रिकॉर्ड भी सुरक्षित नहीं रखता।

Bash में हर पाइपलाइन एग्जिट स्टेटस कैसे कैप्चर करें?

Bash में पाइपलाइन के तुरंत बाद इसे कॉपी करें: statuses=("${PIPESTATUS[@]}")। इसे echo, local, $? पढ़ने वाली असाइनमेंट या किसी भी दूसरी कमांड से पहले करें, क्योंकि अगली कमांड ऐरे की सामग्री बदल देती है।

क्या macOS Bash, PIPESTATUS को सपोर्ट करता है?

macOS में Bash 3.2 शामिल है, जो PIPESTATUS और set -o pipefail दोनों को सपोर्ट करता है। फिर भी यह न मानें कि /bin/sh Bash है। रिमोट प्रोग्राम को bash -s के रूप में चलाएं या स्पष्ट पाथ से Bash स्क्रिप्ट चलाएं।

pipefail कभी-कभी 141 क्यों लौटाता है?

141 स्टेटस का अर्थ अक्सर यह होता है कि किसी प्रोसेस को SIGPIPE मिला। यह तब सामान्य हो सकता है जब नीचे वाली कमांड जानबूझकर जल्दी पढ़ना बंद कर दे, जैसे head। इसे तभी अपेक्षित मानें जब पाइपलाइन का जल्दी रुकना आपके डिजाइन और टेस्ट का हिस्सा हो। अन्यथा इसकी जांच किसी भी दूसरी विफलता की तरह करें।

क्या SSH के बाद स्थानीय tee पाइपलाइन की भी जांच करनी चाहिए?

नहीं। रिमोट पाइपलाइन और स्थानीय ssh ... | tee log पाइपलाइन अलग हैं। रिमोट wrapper को अपनी स्टेज रिपोर्ट करनी होगी और स्थानीय wrapper को ssh तथा tee दोनों का स्टेटस कैप्चर करना होगा।

क्या pipefail के साथ set -e इस्तेमाल करना चाहिए?

set -e में संदर्भ पर निर्भर कई अपवाद हैं, खासकर conditionals, command substitutions और pipelines के साथ। यह उपयोगी सबूत इकट्ठा करने से पहले स्क्रिप्ट रोक सकता है। इसलिए कार्रवाई वाली पाइपलाइनों के लिए स्पष्ट स्टेटस कैप्चर करें और set -e को सरल स्क्रिप्ट संरचना तक सीमित रखें।

रिमोट पाइपलाइन चलने के बाद एजेंट को क्या मिलना चाहिए?

ऐसा स्थिर, मशीन-पठनीय रिकॉर्ड इस्तेमाल करें जिसमें पाइपलाइन और उसकी हर स्टेज का नाम हो। किसी आवश्यक स्टेज के विफल होने पर nonzero एग्जिट लौटाएं। इस रिकॉर्ड को मानव-केंद्रित कमांड आउटपुट से अलग रखें, ताकि एजेंट किसी सुंदर आखिरी पंक्ति को सफलता का संकेत न समझे।

क्या पाइपलाइन की किसी एक स्टेज का nonzero एग्जिट कोड अनदेखा कर सकते हैं?

हर nonzero स्टेटस को सामान्य विफलता न मानें। तय करें कि क्या किसी स्टेज पर grep का no match वाला 1 जैसे स्टेटस स्वीकार्य है, फिर यह नियम उसी स्टेज के साथ लिखें। सामान्य || true उन विफलताओं को छिपा देता है जिन्हें आप सामने लाना चाहते थे।

कैसे जांचें कि एजेंट SSH की झूठी सफलता रिपोर्ट नहीं कर सकता?

एक अस्थायी रिमोट स्क्रिप्ट में जानबूझकर विफल producer, सफल middle stage और सफल final stage रखें। सटीक status vector, wrapper का nonzero एग्जिट और स्थानीय SSH स्टेटस की पुष्टि करें। सफलता वाला मामला और जानबूझकर बनाया गया SIGPIPE मामला अलग-अलग टेस्ट करें।

Sallyport

Sallyport आपके AI एजेंट के लिए API कॉल और SSH कमांड चलाता है। कुंजियाँ आपके Mac पर एक लोकल वॉल्ट में रहती हैं; आप हर रन को स्वीकृत करते हैं और हर क्रिया एक सीलबंद जर्नल में दर्ज होती है।

© 2026 Sallyport · Apache-2.0 के तहत ओपन सोर्स · Oleg Sotnikov