"रिवर्स ऑर्डर" में ब्रेस विस्तार लागू करें


21

उदाहरण के लिए {a..c}{1..3}फैलता है a1 a2 a3 b1 b2 b3 c1 c2 c3

अगर मैं प्रिंट करना चाहता था a1 b1 c1 a2 b2 c2 a3 b3 c3, तो क्या ऐसा करने का एक समान तरीका है? सबसे सरल तरीका क्या है?

जवाबों:


30

तुम यह कर सकते थे:

$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3

जो तब शेल को मूल्यांकन करने के लिए कहता है:

echo {a..c}1 {a..c}2 {a..c}3

10

इस विशेष मामले के लिए, मुझे लगता है कि स्टीफन चेज़लस द्वारा दिया गया विकल्प सबसे अच्छा है।

दूसरी ओर, जब आप अधिक जटिल चीजों का विस्तार करते हैं, तो यह विकल्प अच्छा नहीं होता है। तो, आप इसे प्राप्त कर सकते हैं:

$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '

कौन सा रिटर्न:

a1 b1 c1 a2 b2 c2 a3 b3 c3

थोड़ा गड़बड़ लगता है, लेकिन अब, मेरे पास आदेश में एक बड़ा नियंत्रण है, बस ऊपर दिए गए कमांड में दो चार्ट बदल रहा है; उदाहरण के लिए:

$ echo {a..b}{1..2}{a..b}{1..2}

इसका विस्तार होगा:

a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2

मान लीजिए कि मैं 1दूसरे विस्तार में सभी चाहता हूं , तो 2:

$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.2 | tr '\0' ' '
a1a1 a1a2 a1b1 a1b2 b1a1 b1a2 b1b1 b1b2 a2a1 a2a2 a2b1 a2b2 b2a1 b2a2 b2b1 b2b2

मान लीजिए कि मैं aतीसरे विस्तार में सभी चाहता हूं , तो b:

$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.3,1.3 | tr '\0' ' '
a1a1 a1a2 a2a1 a2a2 b1a1 b1a2 b2a1 b2a2 a1b1 a1b2 a2b1 a2b2 b1b1 b1b2 b2b1 b2b2

मान लीजिए कि मुझे 1चौथे विस्तार में सभी चाहिए , तो 2:

$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.4,1.4 | tr '\0' ' '
a1a1 a1b1 a2a1 a2b1 b1a1 b1b1 b2a1 b2b1 a1a2 a1b2 a2a2 a2b2 b1a2 b1b2 b2a2 b2b2

मान लीजिए कि मैं सभी को 1aबीच में चाहता हूं , फिर 1b, फिर 2a, तब 2b:

$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.3 | tr '\0' ' '
a1a1 a1a2 b1a1 b1a2 a1b1 a1b2 b1b1 b1b2 a2a1 a2a2 b2a1 b2a2 a2b1 a2b2 b2b1 b2b2

तुम भी, बस के रूप में आसानी से, ऊपर विस्तार में किसी भी आदेश को उल्टा कर सकते हैं, बस rपिछले कमांड में जोड़ सकते हैं ; उदाहरण के लिए, अंतिम एक:

$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -rzk 1.2,1.3 | tr '\0' ' '
b2b2 b2b1 a2b2 a2b1 b2a2 b2a1 a2a2 a2a1 b1b2 b1b1 a1b2 a1b1 b1a2 b1a1 a1a2 a1a1

नोट 1 : आमतौर पर, यदि यह अंतिम विस्तार तर्कों की सूची के रूप में उपयोग किया जा रहा है, तो अनुगामी स्थान कोई समस्या नहीं है; लेकिन अगर आप इससे छुटकारा पाना चाहते हैं, तो आप ऊपर दिए गए किसी भी आदेश में जोड़ सकते हैं, उदाहरण के लिए| sed 's/ $//' ; या फिर| sed 's/ $/\n/', एक के लिए उस अनुगामी स्थान को बदलने के लिएnewline

नोट 2 : ऊपर के उदाहरणों में, मैं दो तत्वों के उपसमुच्चय का उपयोग करता हूं (जैसे: {a, b} और {1,2} ) केवल अवधारणा के प्रमाण में सरलता के लिए: आप किसी भी परिमित लंबाई के सबसेट का उपयोग कर सकते हैं, और संगत आदेश, तुलनीय होगा।


5

bash, ksh, zsh

एक लाइनर जो काम करता है (बैश, ksh, zsh) (सभी गोले रिवर्स में "ब्रेस विस्तार" कर सकते हैं):

$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3

एक विकल्प जो उपयोग करता है eval(जो कि अभी भी bash, ksh, zsh और अधिक गुप्त हो सकता है) के लिए है:

$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3

यह समझने के लिए कि क्या होता है, की जगह evalके साथ echo:

$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3

निष्पादित कमांड (विस्तार के बाद) वास्तव में है echo {a..c}1 {a..c}2 {a..c}3। जो आप चाहते हैं / जरूरत के रूप में फैलता है।

सभी गोले

"ब्रेस एक्सपैंशन" के बिना कई गोले हैं, इसलिए, "सभी गोले" के लिए इसका उपयोग करना संभव नहीं है। हमें एक लूप की आवश्यकता है (एक सफेद जगह के साथ):

$ for i in 1 2 3; do for j in a b c; do printf "%s%s " "$j" "$i"; done; done; echo
a1 b1 c1 a2 b2 c2 a3 b3 c3 

यदि आपके पास कोई अनुगामी स्थान नहीं होना चाहिए:

s=""
for i in 1 2 3; do
    for j in a b c; do
        printf "%s%s%s" "$s" "$j" "$i"
        s=" "
    done
done
echo

प्रिंटों

a1 b1 c1 a2 b2 c2 a3 b3 c3

यदि आपको कई मूल्यों के लिए ऐसा करने की आवश्यकता है, तो हमें संख्याओं की सूची बनाने के लिए ब्रेस विस्तार के समान कुछ का उपयोग करने की आवश्यकता है $(seq 10)। और, जैसा कि seq अक्षरों की एक सूची उत्पन्न नहीं कर सकता है, हमें उत्पन्न संख्याओं को ascii में बदलने की आवश्यकता है:

s=""
for i in $(seq 4); do
    for j in $(seq 5); do
        printf "%s\\$(printf %03o $((96+j)))%s" "$s" "$i"
        s=" "
    done
done
echo

प्रिंट:

a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4

आप yash -o braceexpandसूची में भी जोड़ सकते हैं ।
स्टीफन चेजलस

@ स्टीफनचैलेज मुझे यकीन नहीं है कि मुझे करना चाहिए। कमांड लिनक्स में yash -o braceexpand -c 'echo {3..1}{c..a}'प्रिंट करता 3{c..a} 2{c..a} 1{c..a}है। पूर्ण "ब्रेस विस्तार" नहीं।
इसहाक

3
{a..c}1 {a..c}2 {a..c}3

ब्रेस विस्तार {a..c}{1..3}को दाएं से बाएं फैला दिया जाता है, इसलिए आपको पहले मिलता है a{1..3} b{1..3} c{1..3}और फिर अक्षरों को संख्याओं के साथ जोड़ दिया जाता है a1 a2 a3 b1 b2 b3 c1 c2 c3। आप जो आदेश चाहते हैं, उसे पाने के लिए आपको ऊपर की थोड़ी लंबी अभिव्यक्ति का उपयोग करना होगा।


यदि आप इसे "संख्याओं" की एक बड़ी श्रृंखला के लिए करना चाहते थे, तो यह व्यावहारिक नहीं होगा।
रुबेन गोनालो मोरो

3
@ RUBENGON wouldn'tALOMOROUÇO नहीं, यह नहीं होगा, और यदि आप इसे बड़ी संख्या के लिए कर रहे हैं, तो मैं एक दोहरे लूप की तरह एक वैकल्पिक दृष्टिकोण का उपयोग करने का सुझाव दूंगा। यह कई हजारों संयोजनों के लिए काम करेगा, जबकि एक ब्रेस कुछ संदर्भों में मेरी ट्रिगर "तर्क सूची बहुत लंबी" का विस्तार करता है।
Kusalananda

2

एक लूप का उपयोग करना:

for n in {1..3}; do printf '%s\n' {a..c}"$n"; done

यह आपके पहले विस्तार के माध्यम से लूप करेगा और फिर दूसरे के साथ प्रत्येक वर्ण का विस्तार करेगा।

यदि आपको एक पंक्ति में सभी आउटपुट की आवश्यकता है, तो आप इसे हटा सकते हैं \n:

for n in {1..3}; do printf '%s ' {a..c}"$n"; done

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


1
एक लूप समाधान के लिए इतने नीचे वोट क्यों?
इसहाक

दुह मैंने प्रश्न गलत पढ़ा होगा। अपडेट किया गया
जेसी_ब

2

यह आपके सरल मामले के लिए काम करता है और इसे बढ़ाया जा सकता है, लेकिन यह जल्दी से हाथ से निकल जाएगा। अधिक जटिल मामले जिनके लिए यह काम नहीं करेगा निर्माण के लिए आसान है।

ब्रेस विस्तार के क्रम को उल्टा करें, फिर पात्रों को स्वैप करें:

echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'

@ मुरु: उफ़। फिक्स्ड। धन्यवाद।
अगली सूचना तक रोक दिया गया।

@ आईसैक: मैंने ट्रेलिंग स्पेस तय किया।
अगली सूचना तक रोक दिया गया।

0

एक सरल तरीका यह होगा कि आप सॉर्ट का उपयोग करें (1.2,1.2 का मतलब है कि आप एक पात्र को दूसरी स्थिति में ले जाते हैं और उसी स्थान पर समाप्त होते हैं)।

$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2
a1
b1
c1
a2
b2
c2
a3
b3
c3

यदि आप उन्हें एक पंक्ति में चाहते हैं, तो आप tr का उपयोग कर सकते हैं:

$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2|tr '\n' ' '
a1 b1 c1 a2 b2 c2 a3 b3 c3

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.