बाश में अंतिम कमांड से पुन: उत्पादन


180

क्या बाश कमांड का आउटपुट किसी भी रजिस्टर में संग्रहीत है? उदाहरण $?के बाहर निकलने की स्थिति के बजाय आउटपुट कैप्चरिंग के समान कुछ ।

मैं आउटपुट को किसी चर के साथ असाइन कर सकता हूं:

output=$(command)

लेकिन यह अधिक टाइपिंग है ...


जवाबों:


184

आप उपयोग कर सकते हैं $(!!) करने के लिए पुन: परिकलन (नहीं फिर से उपयोग) पिछले आदेश के उत्पादन में।

!!अपनी ही कार्यान्वित पर पिछले आदेश।

$ echo pierre
pierre
$ echo my name is $(!!)
echo my name is $(echo pierre)
my name is pierre

9
आप $(your_cmd)बैकटिक्स का उपयोग करके अपने आप को टाइपिंग से बचा सकते हैं : `your_cmd`गन्न बैश मैनुअल के अनुसार वे कार्यात्मक रूप से समान हैं। बेशक यह @memecs द्वारा उठाए गए चेतावनी के अधीन भी है

व्यवहार में, कमांड का आउटपुट नियतात्मक होता है, इसलिए मैं इसे पुनर्संयोजन से अधिक नहीं करूंगा। यह निश्चित रूप से उपयोगी है जब आप कुछ करना चाहते हैं जैसे git diff $(!!)कि पिछले कमांड एक findआह्वान था ।
श्रीधर सरनोबत

जाहिरा तौर $()पर backticks के बजाय उपयोग करने के लिए अच्छे कारण हैं । लेकिन शायद नींद को खोने के लिए कुछ भी नहीं। github.com/koalaman/shellcheck/wiki/SC2006
माइकल क्रेंशॉ

1
@ user2065875 हालांकि बैश में अभी भी बैकटिक्स काम करते हैं, वे इसके पक्ष में पदावनत हो जाते हैं $()
कुरुचिंस्की

87

जवाब न है। बैश किसी भी आउटपुट को किसी भी पैरामीटर या किसी भी ब्लॉक को उसकी मेमोरी पर आवंटित नहीं करता है। इसके अलावा, आपको केवल इसके स्वीकृत इंटरफ़ेस संचालन द्वारा बैश का उपयोग करने की अनुमति है। जब तक आप इसे हैक नहीं करते बश का निजी डेटा सुलभ नहीं है।


2
क्या यह संभव है कि कुछ कस्टम बैश 'मिडलवेयर' फंक्शन हो जो हर कमांड से पहले चलता हो, जहां यह सब होता है, जिसके परिणामस्वरूप आउटपुट को उस चीज़ से बचाया जाता है जो एक आंतरिक क्लिपबोर्ड के रूप में कार्य करता है (जैसे, BASH_CLIPBOARD)?
पैट नीडम

@PatNeedham यकीन नहीं होता। लोड करने योग्य मॉड्यूल की जाँच करें। देखें कि क्या आप एक लिख सकते हैं।
konsolebox

11

ऐसा करने का एक तरीका है trap DEBUG:

f() { bash -c "$BASH_COMMAND" >& /tmp/out.log; }
trap 'f' DEBUG

अब सबसे हाल ही में निष्पादित कमांड के स्टडआउट और स्टेडर में उपलब्ध होगा /tmp/out.log

केवल नकारात्मक पक्ष यह है कि यह एक कमांड को दो बार निष्पादित करेगा: एक बार आउटपुट और त्रुटि को /tmp/out.logएक बार और आम तौर पर रीडायरेक्ट करने के लिए । संभवतः इस व्यवहार को रोकने का कोई तरीका है।


10
इसलिए जब मैं टाइप करता हूं rm -rf * && cd .., तो न केवल वर्तमान डायरेक्टरी, बल्कि पेरेंट डायर भी मिट जाएगा ?? यह दृष्टिकोण मुझे बहुत खतरनाक लगता है
फिल्प

1
अब मैं इस कार्रवाई को कैसे पूर्ववत करूं?
कार्तिक चौहान

5
@ कार्तिकचौहान: बस करोtrap '' DEBUG
शुभ नवरात्रि १३’१। की रात १३:१३

7

यदि आप मैक पर हैं, और एक चर लिखने के बजाय क्लिपबोर्ड में अपने आउटपुट को स्टोर करने में कोई आपत्ति नहीं है, तो आप एक वर्कअराउंड के रूप में pbcopy और pbpaste का उपयोग कर सकते हैं।

उदाहरण के लिए, ऐसा करने के बजाय एक फ़ाइल खोजने के लिए और दूसरी फ़ाइल के साथ उसकी सामग्री को अलग करने के लिए:

$ find app -name 'one.php' 
/var/bar/app/one.php

$ diff /var/bar/app/one.php /var/bar/two.php

आप ऐसा कर सकते हैं:

$ find app -name 'one.php' | pbcopy
$ diff $(pbpaste) /var/bar/two.php

/var/bar/app/one.phpजब आप पहली कमांड चलाते हैं तो स्ट्रिंग क्लिपबोर्ड में होती है।

वैसे, पंजाब में pbcopyऔर pbpasteपेस्टबोर्ड, क्लिपबोर्ड के लिए एक पर्याय के लिए स्टैंड।


1
on linux $ find app -name 'one.php' | xclip $ diff $(xclip -o) /var/bar/two.php
si-mikey

दिलचस्प, मैं pbpasteकमांड प्रतिस्थापन के साथ एक साथ उपयोग करने के बारे में कभी नहीं सोचा था ।
श्रीधर सरनोबत

क्या होगा अगर मैं पहले और बाद में महसूस करता हूं कि यह अक्षम था, मैं दूसरे विकल्प के साथ पुन: निर्देशित के बिना कम्प्यूटेशनल समय कैसे बचा सकता हूं?
नेल्सनगॉन

4

अनुभव के जवाब से प्रेरित, जो मुझे लगता है कि वास्तव में स्वीकार्य नहीं है क्योंकि यह प्रत्येक कमांड को दो बार चलाता है।

save_output() { 
   exec 1>&3 
   { [ -f /tmp/current ] && mv /tmp/current /tmp/last; }
   exec > >(tee /tmp/current)
}

exec 3>&1
trap save_output DEBUG

इस तरह अंतिम कमांड का आउटपुट / tmp / last होता है और कमांड को दो बार नहीं कहा जाता है।


1
एक नकारात्मक पहलू यह है कि आपके आदेशों में से कोई भी यह नहीं सोचता है कि वे अब एक छोटे से चल रहे हैं, जिसका अर्थ है कि आपको उपयोगिताओं के लिए रंग कोड प्राप्त करने के लिए विशेष ध्यान देने की आवश्यकता है जैसे grepया git diff+1 वैसे भी
मार्टी नील

2

जैसे konsolebox ने कहा, आपको अपने आप को bash में हैक करना होगा। यहाँ एक बहुत अच्छा उदाहरण है कि कोई इसे कैसे प्राप्त कर सकता है। स्टैडरड रिपॉजिटरी (वास्तव में स्टैडआउट को रंग देने के लिए है) इसे बनाने के निर्देश देता है।

मैंने इसे एक कोशिश दी: कुछ नए फ़ाइल डिस्क्रिप्टर को परिभाषित करना .bashrcजैसे अंदर

exec 41>/tmp/my_console_log

(संख्या मनमानी है) और stderred.cतदनुसार संशोधित करें ताकि सामग्री भी fd 41 को लिखी जाए। यह एक तरह का काम है, लेकिन इसमें एनयूएल बाइट्स, अजीब फॉर्मेटिंग का भार है और मूल रूप से द्विआधारी डेटा है, जो पठनीय नहीं है। हो सकता है कि C की अच्छी समझ रखने वाला कोई व्यक्ति इसे आजमा सकता है।

यदि हां, तो अंतिम मुद्रित लाइन प्राप्त करने के लिए आवश्यक सब कुछ है tail -n 1 [logfile]


1

हाँ, हर बार सहमत होने पर अतिरिक्त लाइनें क्यों लिखें। आप इनपुट पर वापस आ सकते हैं, लेकिन इनपुट में आउटपुट (1> & 0) नहीं है। इसके अलावा, आप प्रत्येक फ़ाइल में उसी के लिए बार-बार एक फ़ंक्शन लिखना नहीं चाहेंगे।

यदि आप फ़ाइलों को कहीं भी निर्यात नहीं कर रहे हैं और इसे केवल स्थानीय रूप से उपयोग करने का इरादा रखते हैं, तो आप फ़ंक्शन की घोषणा के लिए टर्मिनल सेट-अप कर सकते हैं। आपको फंक्शन को ~/.bashrcफाइल या फाइल में जोड़ना है ~/.profile। दूसरे मामले में, आप सक्षम करने की आवश्यकता Run command as login shellसे Edit>Preferences>yourProfile>Command

एक सरल कार्य करें, कहें:

get_prev()
{
    # option 1: create an executable with the command(s) and run it
    echo $* > /tmp/exe
    bash /tmp/exe > /tmp/out

    # option 2: if your command is single command (no-pipe, no semi-colons), still it may not run correct in some exceptions
    #echo `$*` > /tmp/out

    # return the command(s) outputs line by line
    IFS=$(echo -en "\n\b")
    arr=()
    exec 3</tmp/out
    while read -u 3 -r line
    do
        arr+=($line)
        echo $line
    done
    exec 3<&-
}

मुख्य स्क्रिप्ट में:

#run your command:
cmd="echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"
get_prev $cmd
#or simply
get_prev "echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"

बैश पिछले दायरे से बाहर भी चर बचाता है:

#get previous command outputs in arr
for((i=0; i<${#arr[@]}; i++)); do echo ${arr[i]}; done

1

बहुत ही सरल उपाय

एक जिसे मैंने सालों से इस्तेमाल किया है।

स्क्रिप्ट (अपने में जोड़ें .bashrcया .bash_profile)

# capture the output of a command so it can be retrieved with ret
cap () { tee /tmp/capture.out}

# return the output of the most recent command that was captured by cap
ret () { cat /tmp/capture.out }

प्रयोग

$ find . -name 'filename' | cap
/path/to/filename

$ ret
/path/to/filename

मैं | capअपने सभी आदेशों के अंत में जोड़ना चाहता हूं। इस तरह जब मुझे लगता है कि मैं एक धीमी गति से चल रही कमांड के आउटपुट पर टेक्स्ट प्रोसेसिंग करना चाहता हूं तो मैं इसे हमेशा प्राप्त कर सकता हूं res


का फ़ायदा क्या है cat -में cap () { cat - | tee /tmp/capture.out}यहाँ? क्या cap () { tee /tmp/capture.out }कोई हिचकी मुझे याद आ रही है?
वॉटसन

1
@Watson अच्छा बिंदु! मुझे नहीं पता कि मेरे पास ऐसा क्यों है, संभावना है। क्या मुझे cat - | cat - | cat -इसे और अधिक रोचक बनाने के लिए पहले से जोड़ना चाहिए ? 😉 मैं इसे ठीक करने के बाद एक बार यह सुनिश्चित करने के लिए परीक्षण करूंगा कि यह वास्तव में एक झगड़ा है
कॉनर

0

निश्चित रूप से इसके लिए आपको इसकी आवश्यकता नहीं है, इसलिए यह उत्तर प्रासंगिक नहीं हो सकता है। आप हमेशा एक कमांड के आउटपुट को बचा सकते हैं: netstat >> output.txtलेकिन मुझे नहीं लगता कि आप वही देख रहे हैं जो आप चाहते हैं।

हालांकि प्रोग्रामिंग प्रोग्रामिंग विकल्प हैं; आप बस उस कमांड के चलने के बाद ऊपर दिए गए टेक्स्ट फ़ाइल को पढ़ने के लिए एक प्रोग्राम प्राप्त कर सकते हैं और इसे एक चर के साथ जोड़ सकते हैं, और रूबी, मेरी पसंद की भाषा में, आप 'बैकटिक्स' का उपयोग करके कमांड आउटपुट से एक वेरिएबल बना सकते हैं:

output = `ls`                       #(this is a comment) create variable out of command

if output.include? "Downloads"      #if statement to see if command includes 'Downloads' folder
print "there appears to be a folder named downloads in this directory."
else
print "there is no directory called downloads in this file."
end

इसे एक .rb फ़ाइल में चिपकाएं और इसे चलाएं: ruby file.rbऔर यह कमांड से बाहर एक वैरिएबल बनाएगा और आपको इसमें हेरफेर करने की अनुमति देगा।


9
"सुनिश्चित नहीं हैं कि वास्तव में क्या आप के लिए यह आवश्यकता होगी, कर रहे हैं" ठीक है, कहते हैं कि तुम (जिसके द्वारा मैं मतलब मैं ) सिर्फ एक लंबी अवधि स्क्रिप्ट चलाने पर, उत्पादन खोज करना चाहते हैं, और मूर्खता से निष्पादित करने से पहले उत्पादन रीडायरेक्ट करने के लिए भूल गया था। अब मैं स्क्रिप्ट को फिर से चलाए बिना अपनी मूर्खता को दूर करने की कोशिश करना चाहता हूं।
१५:०५ पर

0

मेरे पास एक विचार है कि मेरे पास तुरंत लागू करने का प्रयास करने का समय नहीं है।

लेकिन अगर आप निम्नलिखित की तरह कुछ करते हैं:

$ MY_HISTORY_FILE = `get_temp_filename`
$ MY_HISTORY_FILE=$MY_HISTORY_FILE bash -i 2>&1 | tee $MY_HISTORY_FILE
$ some_command
$ cat $MY_HISTORY_FILE
$ # ^You'll want to filter that down in practice!

IO बफ़रिंग के साथ समस्याएँ हो सकती हैं। इसके अलावा फ़ाइल बहुत बड़ी हो सकती है। इन समस्याओं के समाधान के लिए एक व्यक्ति को सामने आना होगा।


0

मुझे लगता है कि स्क्रिप्ट कमांड का उपयोग करने से मदद मिल सकती है। कुछ इस तरह,

  1. स्क्रिप्ट -c बैश -qf फीफो_पिड

  2. पार्स करने के बाद सेट करने के लिए बैश सुविधाओं का उपयोग करना।


0

यदि आप पिछली कमांड को फिर से स्थापित नहीं करना चाहते हैं, तो आप एक मैक्रो बना सकते हैं जो वर्तमान टर्मिनल बफर को स्कैन करता है, अंतिम-आउटपुट के -apppposed- अनुमान का अनुमान लगाने की कोशिश करता है, इसे क्लिपबोर्ड पर कॉपी करता है और अंत में इसे टर्मिनल पर टाइप करता है।

इसका उपयोग साधारण आदेशों के लिए किया जा सकता है जो आउटपुट की एक पंक्ति को लौटाते हैं (उबंटू 18.04 के साथ परीक्षण किया गया gnome-terminal)।

स्थापित करें निम्नलिखित उपकरण: xdootool, xclip,ruby

में gnome-terminalजाने के लिए Preferences -> Shortcuts -> Select allऔर इसे करने के लिए सेट करें Ctrl+shift+a

निम्नलिखित रूबी स्क्रिप्ट बनाएँ:

cat >${HOME}/parse.rb <<EOF
#!/usr/bin/ruby
stdin = STDIN.read
d = stdin.split(/\n/)
e = d.reverse
f = e.drop_while { |item| item == "" }
g = f.drop_while { |item| item.start_with? "${USER}@" }
h = g[0] 
print h
EOF

कीबोर्ड सेटिंग्स में निम्नलिखित कीबोर्ड शॉर्टकट जोड़ें:

bash -c '/bin/sleep 0.3 ; xdotool key ctrl+shift+a ; xdotool key ctrl+shift+c ; ( (xclip -out | ${HOME}/parse.rb ) > /tmp/clipboard ) ; (cat /tmp/clipboard | xclip -sel clip ) ; xdotool key ctrl+shift+v '

उपरोक्त शॉर्टकट:

  • वर्तमान टर्मिनल बफर को क्लिपबोर्ड पर कॉपी करता है
  • अंतिम कमांड (केवल एक लाइन) का आउटपुट निकालता है
  • इसे वर्तमान टर्मिनल में टाइप करता है
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.