क्या सब-कमांड का उपयोग किए बिना शेल कमांड प्रतिस्थापन करना संभव है?


11

मेरे पास एक परिदृश्य है जो बिना सबस्क्रिप्शन का उपयोग किए हुए कमांड प्रतिस्थापन के लिए कहता है। मेरे पास इस तरह का एक निर्माण है:

pushd $(mktemp -d)

अब मैं एक बार में अस्थायी निर्देशिका से बाहर निकलना और निकालना चाहता हूं:

rmdir $(popd)

हालाँकि यह काम नहीं करता है क्योंकि popdपॉपर्ड डायरेक्टरी को वापस नहीं करता है (यह नया, अब करंट, डाइरेक्टरी लौटाता है) और इसलिए भी कि यह सब-सब्स्क्रिप्शन में किया जाता है।

कुछ इस तरह

dirs -l -1 ; popd &> /dev/null

पॉप की गई निर्देशिका वापस कर देगी लेकिन इसका उपयोग इस तरह नहीं किया जा सकता है:

rmdir $(dirs -l -1 ; popd &> /dev/null)

क्योंकि popdवसीयत केवल उपधारा को प्रभावित करेगी। ऐसा करने की क्षमता क्या है:

rmdir { dirs -l -1 ; popd &> /dev/null; }

लेकिन यह अमान्य सिंटैक्स है। क्या इस प्रभाव को प्राप्त करना संभव है?

(ध्यान दें: मुझे पता है कि मैं एक चर में अस्थायी निर्देशिका को बचा सकता हूं; मैं ऐसा करने की आवश्यकता से बचने और प्रक्रिया में कुछ नया सीखने की कोशिश कर रहा था!)


1
मैं निर्देशिका को एक चर में सहेजता हूँ; इस तरह, एक trapहैंडलर निर्देशिका को साफ कर सकता है प्रक्रिया को एक सिग्नल द्वारा पोक्ड किया जाना चाहिए।
थ्रीग

जवाब है नहीं
h0tw1r3

यह ऐसा दिखता है fish, कमांड प्रतिस्थापन के बराबर, ()बाहरी शेल के फ़ोल्डर को बदलता है। यह आमतौर पर कष्टप्रद है, लेकिन इस तरह के मामलों में यह उपयोगी है, मुझे यकीन है।
trysis 16

जवाबों:


10

आपके प्रश्न के शीर्षक का चुनाव थोड़ा भ्रमित करने वाला है।

pushd/ popd, cshद्वारा कॉपी की गई सुविधा bashऔर zsh, याद की गई निर्देशिकाओं के ढेर को प्रबंधित करने का एक तरीका है।

pushd /some/dir

एक स्टैक पर वर्तमान कार्यशील निर्देशिका को धकेलता है , और फिर वर्तमान कार्य निर्देशिका को बदलता है (और फिर /some/dirउस स्टैक की सामग्री के बाद प्रिंट करता है (स्थान-पृथक)।

popd

स्टैक की सामग्री को प्रिंट करता है (फिर से, अंतरिक्ष अलग हो जाता है) और फिर स्टैक के शीर्ष तत्व में बदल जाता है और इसे स्टैक से पॉप करता है।

(यह भी ध्यान रखें कि कुछ निर्देशिकाओं को उनके ~/xया ~user/xअंकन के साथ वहां प्रस्तुत किया जाएगा )।

तो अगर स्टैक वर्तमान में है /aऔर /b, वर्तमान निर्देशिका है /hereऔर आप चल रहे हैं:

 pushd /tmp/whatever
 popd

pushdप्रिंट करेगा /tmp/whatever /here /a /bऔर popdआउटपुट करेगा /here /a /b, नहीं /tmp/whatever। यह कमांड प्रतिस्थापन का उपयोग करने से स्वतंत्र है या नहीं। popdपिछले निर्देशिका के पथ प्राप्त करने के लिए इस्तेमाल नहीं किया जा सकता है, और सामान्य रूप में इसके उत्पादन के बाद संसाधित नहीं किया जा सकता है (देखें $dirstackया $DIRSTACKकुछ गोले की सरणी कि निर्देशिका ढेर के तत्वों तक पहुँचने के लिए, हालांकि)

शायद आप चाहते हैं:

pushd "$(mktemp -d)" &&
popd &&
rmdir "$OLDPWD"

या

cd "$(mktemp -d)" &&
cd - &&
rmdir "$OLDPWD"

हालाँकि, मैं उपयोग करूँगा:

tmpdir=$(mktemp -d) || exit
(
  cd "$tmpdir" || exit # in a subshell 
  # do what you have to do in that tmpdir
)
rmdir "$tmpdir"

किसी भी मामले में, एक उपधारा में pushd "$(mktemp -d)"नहीं चलता pushdहै। यदि यह किया जाता है, तो यह कार्यशील निर्देशिका को बदल नहीं सकता है। कि mktempएक उप में चलता है। चूंकि यह एक अलग कमांड है, इसलिए इसे एक अलग प्रक्रिया में चलना होगा। यह एक पाइप पर अपना आउटपुट लिखता है, और शेल प्रक्रिया पाइप के दूसरे छोर पर पढ़ती है।

ksh93 कमांड बनने पर अलग प्रक्रिया से बच सकता है, लेकिन वहां भी, यह अभी भी एक सबस्लेम (एक अलग काम करने का माहौल) है, जो इस समय को आमतौर पर फोर्किंग द्वारा प्रदान किए गए अलग-अलग वातावरण पर भरोसा करने के बजाय अनुकरण किया जाता है। उदाहरण के लिए, में ksh93, a=0; echo "$(a=1; echo test)"; echo "$a"कोई कांटा शामिल नहीं है, लेकिन फिर भी echo "$a"आउटपुट 0

यहाँ, अगर आप के उत्पादन में संग्रहीत करना चाहते हैं mktempएक चर में, एक ही समय के रूप में आप इसे पारित पर pushd, साथ zsh, आप कर सकता है:

pushd ${tmpdir::="$(mktemp -d)"}

अन्य बॉर्न-जैसे गोले के साथ:

unset tmpdir
pushd "${tmpdir=$(mktemp -d)}"

या $(mktemp -d)इसे एक चर में स्पष्ट रूप से संग्रहीत किए बिना कई बार के आउटपुट का उपयोग करने के लिए , आप zshअनाम कार्यों का उपयोग कर सकते हैं :

(){pushd ${1?} && cd - && rmdir $1} "$(mktemp -d)"

मैं समझता हूं pushdऔर popdजैसा कि आप वर्णन करते हैं और काम करने के लिए वे कमांड प्रतिस्थापन से स्वतंत्र हैं - वहां कोई भ्रम नहीं है! हालाँकि, आपने खुद की समस्या का खुलासा करके जवाब दिया $OLDPWD। मैं कर सकता हूँ popd; rmdir $OLDPWD। वह मेरी समस्या का जवाब है - बाकी सब कुछ जो मैंने सोचा था उसकी पुष्टि करता है। कमांड प्रतिस्थापन इसे हल करने का एक तरीका प्रतीत होता है, लेकिन यह उपधारा के कारण नहीं है और आप बिना सबस्क्रिप्शन के कमांड प्रतिस्थापन नहीं कर सकते हैं, इसलिए OLDPWD को प्रकट करने के लिए धन्यवाद - यह वही है जो मुझे चाहिए!
स्टारफ्री

@starfry, एक उप-शेल में चलने का rmdir $(popd)कारण बनता popdहै जिसका अर्थ है कि यह वर्तमान निर्देशिका को नहीं बदलेगा, लेकिन भले ही यह एक उप-भाग में नहीं चला, लेकिन इसका उत्पादन popdअस्थायी निर्देशिका नहीं होगा, यह अंतरिक्ष से अलग सूची होगी निर्देशिकाओं कि अस्थायी डायर शामिल नहीं है। यह वह जगह है जहां मैं कह रहा हूं कि आप भ्रमित हैं।
स्टीफन चेजलस

लेकिन मुझे लगा कि मैंने अपने प्रश्न में कहा था: "popd popped निर्देशिका को वापस नहीं करता है (यह नया, अब वर्तमान, निर्देशिका) लौटाता है और इसलिए भी क्योंकि यह एक सब-डिले में किया जाता है।" बेशक यह एक सूची देता है, लेकिन सूची में पहला वह है जिसका मैं उल्लेख कर रहा था।
स्टारफ्री

@starfry, ओके सॉरी। मान लीजिए कि मैं सवाल के शीर्षक से भ्रमित था और बाकी को ध्यान से नहीं पढ़ा।
स्टीफन चेज़लस 17

वैसे आपका जवाब अभी भी अच्छा था और मुझे सही दिशा में इशारा किया। मुझे उस शेल चर के बारे में कभी नहीं पता था OLDPWD। मुझे man bashएंड-टू-एंड से पढ़ा हुआ एक दिन याद रखना चाहिए !
स्टारफ्री

2

इसे छोड़ने से पहले आप पहले निर्देशिका को अनलिंक कर सकते हैं:

rmdir "$(pwd -P)" && popd

या

rmdir "$(pwd -P)" && cd ..   # yes, .. is still usable

ध्यान दें कि लेकिन pushdऔर popdवास्तव में इंटरैक्टिव गोले के लिए उपकरण, लिपियों के लिए नहीं कर रहे हैं (इसलिए वे इतनी बातूनी होते हैं, जब वे सफल वास्तविक पटकथा आदेशों चुप हैं)।


0

बैश में, dirsपुशड / पोप विधि द्वारा याद की गई निर्देशिकाओं की सूची प्रदान करें।

इसके अलावा, dirs -1सूची में शामिल अंतिम निर्देशिका को प्रिंट करता है।

इसलिए, निष्पादित करके पहले बनाई गई निर्देशिका को निकालने के लिए pushd $(mktmp -d), उपयोग करें:

rmdir $(dirs -1)

और फिर, popdसूची से पहले ही हटा दी गई निर्देशिका:

popd > /dev/null

सभी एक पंक्ति में:

rmdir $(dirs -1); popd > /dev/null

~/xया ~user/xनोटेशन से बचने के लिए विकल्प (-l) जोड़ना :

rmdir $(dirs -l -1); popd > /dev/null

जो आपके द्वारा मांगी गई रेखा के समान है।
सिवाय इसके कि मैं उपयोग नहीं करूंगा &>क्योंकि यह किसी भी त्रुटि रिपोर्टिंग को छिपा देगा popd

ध्यान दें: निर्देशिका के बाद ही रहेगा rmdirयह है के रूप में pwdउस बिंदु पर। और वास्तव में popdकमांड के बाद अनलिंक किया जाएगा (उपयोग किए गए शेष लिंक नहीं)।


गोले के लिए उपयोग करने के लिए एक विकल्प है, जो चर "ओएलडीपीडब्ल्यूडी" का समर्थन करता है (सबसे बोर्न-जैसे गोले: क्श, बाश, ज़श है $OLDPWD)। यह ध्यान रखना दिलचस्प है कि ksh dirs, pod, pushd को डिफ़ॉल्ट रूप से लागू नहीं करता है (lksh, डैश और अन्य के पास भी popd उपलब्ध नहीं है, इसलिए, यहाँ उपयोग करने योग्य नहीं हैं):

popd && rmdir "$OLDPWD"

या, अधिक मुहावरेदार (ऊपर के रूप में गोले की समान सूची):

popd && rmdir ~-

इसके साथ समस्या, और जो मैं हल करने की कोशिश कर रहा था, वह यह है कि आप rmdirवर्तमान निर्देशिका को नहीं कर सकते हैं , जहाँ आप ऐसा करते समय होंगे। आपको इसे करने से popdपहले प्रभावित करने की आवश्यकता है rmdirलेकिन आपको यह जानना होगा कि आपको क्या निकालना है और popdक्या नहीं। मैं, आप की तरह, सोचा dirs -l -1था कि जवाब था लेकिन पता चला है कि जवाब वास्तव में उपयोग करने के लिए है $OLDPWD
स्टारफ्री

@starfry मेरा मानना ​​है कि सबसे कम उत्तर का उपयोग करना है popd && rmdir ~-:।

@starfry आप वास्तव में वर्तमान निर्देशिका को निकाल सकते हैं, कोई समस्या नहीं है, बशर्ते यह खाली हो (मिटाए बिना)। आप rmdir "$PWD"सब ठीक कह सकते हैं। इसके अलावा, वर्तमान निर्देशिका को पहले से बनाया गया होना चाहिए mktmp -d(यदि pushd $(mktemp -d)पहले से निष्पादित किया गया था) और जिसके pushdलिए pwd चलता है। तो, हाँ, पोप के बाद pushd और पहले बनाई गई निर्देशिका में संग्रहीत किया जाता है $(dirs -1), मैं किसी भी समस्या को देखने में विफल रहता हूं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.