बैश में अंकगणितीय विस्तार का मूल्यांकन


13

निम्न पंक्ति बनाता है file_c-6.txtलेकिन आउटपुट 5:

$ i=5; ls file_a-${i}.txt file_b-${i}.txt > file_c-$(( ++i )).txt; echo $i
5
$ cat file_c-6.txt
file_a-5.txt
file_b-5.txt

यदि कोई निकालता है >तो यह सूची file_c-6.txtऔर आउटपुट होगा 5:

मैं यह नहीं समझ सकता कि यह iपहले उदाहरण में मूल्य क्यों नहीं रखता है ।

$ i=5; ls file_a-${i}.txt file_b-${i}.txt file_c-$(( ++i )).txt; echo $i
file_a-5.txt  file_b-5.txt  file_c-6.txt
6

4
यह विचित्र है।
ग्लेन जैकमैन

2
अगर मैं echoइसके बजाय का उपयोग lsकरता हूं , तो यह दोनों मामलों में दूसरे तरीके से काम करता है।
कोरोबा

1
इस उत्तर में कोड उदाहरण के समान कुछ दिखता है ।
वाइल्डकार्ड

4
/bin/echoअंतर को संरक्षित करता है, इसलिए ऐसा लगता है कि बाहरी कमांड के लिए आउटपुट पुनर्निर्देशन एक उप-प्रकार में होता है।
chepner

2
निश्चित रूप से Bug-bash@gnu.org पर बग रिपोर्ट के लायक; यह वर्तमान में विकास के तहत 4.4 में तय नहीं है।
चेंपनर

जवाबों:


1

यदि आप इसे स्ट्रेस के तहत चलाते हैं, तो आप देख सकते हैं कि उपयोग करने वाला संस्करण lsएक सब-कमांड में कमांड को शुरू करता है , जहां इको का उपयोग करने वाला संस्करण सभी मौजूदा शेल में इसे निष्पादित करता है।

के आउटपुट की तुलना करें

$ strace -f /bin/bash -o trace.txt -c 'i=5; echo $i; echo file_c-$((++i)).txt; echo $i'
5
6
6

विरुद्ध

strace -f /bin/bash -o trace.txt -c 'i=5; echo $i; ls > file_c-$((++i)).txt; echo $i'
5
5

आप पहले में देखेंगे:

1251  execve("/bin/bash", ["/bin/bash", "-c", "i=5; echo $i; echo file_c-$(( ++"...], [/* 19 vars */]) = 0
...
1251  write(1, "5\n", 2)                = 2
1251  write(1, "file_c-6.txt\n", 13)    = 13
1251  write(1, "6\n", 2)                = 2

और दूसरे में:

1258  execve("/bin/bash", ["/bin/bash", "-c", "i=5; echo $i; ls > file_c-$(( ++"...], [/* 19 vars */]) = 0
...
1258  write(1, "5\n", 2)                = 2
...
1258  stat("/bin/ls", {st_mode=S_IFREG|0755, st_size=110080, ...}) = 0
1258  access("/bin/ls", R_OK)           = 0
1258  clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7301f40a10) = 1259
1259  open("file_c-6.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
1259  dup2(3, 1)                        = 1
1259  close(3)                          = 0
1259  execve("/bin/ls", ["ls"], [/* 19 vars */]) = 0
1259  write(1, "71\nbin\nfile_a-5.txt\nfile_b-5.txt"..., 110) = 110
1259  close(1)                          = 0
1259  munmap(0x7f0e81c56000, 4096)      = 0
1259  close(2)                          = 0
1259  exit_group(0)                     = ?
1259  +++ exited with 0 +++
1258  <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 1259
1258  rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f7301570d40}, {0x4438a0, [], SA_RESTORER, 0x7f7301570d40}, 8) = 0
1258  rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
1258  --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1259, si_status=0, si_utime=0, si_stime=0} ---
1258  wait4(-1, 0x7ffd23d86e98, WNOHANG, NULL) = -1 ECHILD (No child processes)
1258  rt_sigreturn()                    = 0
1258  write(1, "5\n", 2)                = 2

इस अंतिम उदाहरण में, आप cloneएक नई प्रक्रिया (1258 -> 1259 से) में देखते हैं, इसलिए अब हम एक उपप्रकार में हैं। File_c-6.txt के खुलने का मतलब है कि हमने सब-हेल्‍थ $((++i))में मूल्‍यांकन किया है, और lsइसके स्‍टैंडआउट के साथ उस फ़ाइल पर अमल किया गया है।

अंत में, हम देखते हैं कि उपप्रकार बाहर निकलता है, हम बच्चे को काटते हैं, फिर हम उसी स्थान पर रहते हैं जहां से हम रवाना हुए थे ... $iसेट 5 से, और यही हम फिर से गूँजते हैं।

(याद रखें कि एक उपप्रकार में परिवर्तनशील परिवर्तन मूल प्रक्रिया के अनुसार नहीं होते हैं, जब तक कि आप बच्चे के परिवर्तनों को हथियाने के लिए माता-पिता में स्पष्ट रूप से कुछ न करें)


बहुत बढ़िया विश्लेषण। एक समाधान वेतन वृद्धि के लिए एक अस्थायी चर का उपयोग करना होगा i=5; j=$(( i + 1 )); ls file_a-${i}.txt file_b-${i}.txt > file_c-${j}.txt; i=${j}; echo $i:।
मर्फी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.