বাশ গ্লোবকে স্ট্রিং ভেরিয়েবল কীভাবে করা যায়?


14

সিস্টেমের তথ্য

ওএস: ওএস এক্স

ব্যাশ: জিএনইউ ব্যাশ, সংস্করণ 3.2.57 (1) -রিলেজ (x86_64-আপেল-ডারউইন 16)

পটভূমি

আমার সমস্ত গিট / নোডেজ প্রকল্প থেকে ডিরেক্টরি এবং ফাইলগুলির একটি সেট বাদ দেওয়ার জন্য আমি টাইম মেশিনটি চাই। আমার প্রকল্পের ডিরেক্টরিগুলি রয়েছে ~/code/private/এবং ~/code/public/তাই আমি এটি করার জন্য ব্যাশ লুপিং ব্যবহার করার চেষ্টা করছি tmutil

সমস্যা

সংক্ষিপ্ত সংস্করণ

আমার যদি একটি গণনাযুক্ত স্ট্রিং ভেরিয়েবল kথাকে তবে আমি কীভাবে এটি লুপের আগে বা ডানদিকে গ্লোব করব?

i='~/code/public/*'
j='*.launch'
k=$i/$j # $k='~/code/public/*/*.launch'

for i in $k # I need $k to glob here
do
    echo $i
done

নীচের দীর্ঘ সংস্করণে, আপনি দেখতে পাবেন k=$i/$j। সুতরাং আমি লুপের জন্য স্ট্রিংটিকে হার্ডকোড করতে পারি না।

দীর্ঘ সংস্করণ

#!/bin/bash
exclude='
*.launch
.classpath
.sass-cache
Thumbs.db
bower_components
build
connect.lock
coverage
dist
e2e/*.js
e2e/*.map
libpeerconnection.log
node_modules
npm-debug.log
testem.log
tmp
typings
'

dirs='
~/code/private/*
~/code/public/*
'

for i in $dirs
do
    for j in $exclude
    do
        k=$i/$j # It is correct up to this line

        for l in $k # I need it glob here
        do
            echo $l
        #   Command I want to execute
        #   tmutil addexclusion $l
        done
    done
done

আউটপুট

তারা গ্লোববেড হয় না। আমি যা চাই তা নয়

~/code/private/*/*.launch                                                                                   
~/code/private/*/.DS_Store                                                                                  
~/code/private/*/.classpath                                                                                 
~/code/private/*/.sass-cache                                                                                
~/code/private/*/.settings                                                                                  
~/code/private/*/Thumbs.db                                                                                  
~/code/private/*/bower_components                                                                           
~/code/private/*/build                                                                                      
~/code/private/*/connect.lock                                                                               
~/code/private/*/coverage                                                                                   
~/code/private/*/dist                                                                                       
~/code/private/*/e2e/*.js                                                                                   
~/code/private/*/e2e/*.map                                                                                  
~/code/private/*/libpeerconnection.log                                                                      
~/code/private/*/node_modules                                                                               
~/code/private/*/npm-debug.log                                                                              
~/code/private/*/testem.log                                                                                 
~/code/private/*/tmp                                                                                        
~/code/private/*/typings                                                                                    
~/code/public/*/*.launch                                                                                    
~/code/public/*/.DS_Store                                                                                   
~/code/public/*/.classpath                                                                                  
~/code/public/*/.sass-cache                                                                                 
~/code/public/*/.settings                                                                                   
~/code/public/*/Thumbs.db                                                                                   
~/code/public/*/bower_components                                                                            
~/code/public/*/build                                                                                       
~/code/public/*/connect.lock                                                                                
~/code/public/*/coverage                                                                                    
~/code/public/*/dist                                                                                        
~/code/public/*/e2e/*.js                                                                                    
~/code/public/*/e2e/*.map                                                                                   
~/code/public/*/libpeerconnection.log                                                                       
~/code/public/*/node_modules                                                                                
~/code/public/*/npm-debug.log                                                                               
~/code/public/*/testem.log                                                                                  
~/code/public/*/tmp                                                                                         
~/code/public/*/typings

একক উদ্ধৃতি বাশে শেল ইন্টারপোলেশন বন্ধ করে দেয়, যাতে আপনি আপনার ভেরিয়েবলটিকে ডাবল-কোট করার চেষ্টা করতে পারেন।
থমাস এন

@ থমাসএন না, এটি কাজ করে না। kএকটি গণনাযুক্ত স্ট্রিং, এবং আমার এটি লুপ অবধি রাখা উচিত। আমার দীর্ঘ সংস্করণ পরীক্ষা করুন।
জন সিউ 18

@ থমাসন আমি সংক্ষিপ্ত সংস্করণটিকে আরও পরিষ্কার করার জন্য আপডেট করেছি।
জন সিউ

উত্তর:


18

আপনি মূল্যায়নের অন্য দফায় সাথে জোর করতে পারেন eval, তবে এটি আসলে প্রয়োজনীয় নয়। (এবং evalআপনার ফাইলের নামগুলিতে যেমন বিশেষ চরিত্র রয়েছে সেই মুহুর্তে গুরুতর সমস্যা হতে শুরু করে $)) সমস্যাটি গ্লোব্বিংয়ের সাথে নয়, তবে টিলডে সম্প্রসারণের ক্ষেত্রে।

Globbing ঘটে পর পরিবর্তনশীল সম্প্রসারণ যদি পরিবর্তনশীল, unquoted এখানে যেমন (*) :

$ x="/tm*" ; echo $x
/tmp

সুতরাং, একই শিরাতে, এটি আপনি যা করেছেন তার সমান এবং কাজ করে:

$ mkdir -p ~/public/foo/ ; touch ~/public/foo/x.launch
$ i="$HOME/public/*"; j="*.launch"; k="$i/$j"
$ echo $k
/home/foo/public/foo/x.launch

তবে টিলড দিয়ে এটি হয় না:

$ i="~/public/*"; j="*.launch"; k="$i/$j"
$ echo $k
~/public/*/*.launch

এটি বাশের পক্ষে স্পষ্টতই নথিবদ্ধ :

বিস্তারের ক্রম: ব্রেস সম্প্রসারণ; টিলডে সম্প্রসারণ, প্যারামিটার এবং পরিবর্তনশীল প্রসারণ, ...

ভেরিয়েবলের প্রসারণের আগে টিলডে সম্প্রসারণ ঘটে তাই ভেরিয়েবলের ভিতরে টিল্ডগুলি প্রসারিত হয় না। ব্যবহারের সহজ সমাধান $HOMEবা পরিবর্তে সম্পূর্ণ পথ instead

(* ভেরিয়েবল থেকে গ্লোবগুলি প্রসারিত করা সাধারণত আপনি চান তা নয়)


আরেকটি বিষয়:

আপনি এখানে নিদর্শনগুলি লুপ করবেন যখন:

exclude="foo *bar"
for j in $exclude ; do
    ...

নোট করুন যে হিসাবে $excludeউদ্ধৃত হয়, এটি উভয় বিভক্ত, এবং এই মুহুর্তে globbed। সুতরাং যদি বর্তমান ডিরেক্টরিটিতে প্যাটার্নের সাথে কিছু মিল রয়েছে তবে তা এতে প্রসারিত হবে:

$ i="$HOME/public/foo"
$ exclude="*.launch"
$ touch $i/real.launch
$ for j in $exclude ; do           # split and glob, no match
    echo "$i"/$j ; done
/home/foo/public/foo/real.launch

$ touch ./hello.launch
$ for j in $exclude ; do           # split and glob, matches in current dir!
    echo "$i"/$j ; done
/home/foo/public/foo/hello.launch  # not the expected result

এটির চারপাশে কাজ করতে, বিভক্ত স্ট্রিংয়ের পরিবর্তে একটি অ্যারে ভেরিয়েবল ব্যবহার করুন:

$ exclude=("*.launch")
$ exclude+=("something else")
$ for j in "${exclude[@]}" ; do echo "$i"/$j ; done
/home/foo/public/foo/real.launch
/home/foo/public/foo/something else

একটি যুক্ত বোনাস হিসাবে, অ্যারে এন্ট্রিগুলিতে বিভাজন নিয়ে সমস্যা ছাড়াই সাদা স্থান থাকতে পারে।


অনুরূপ কিছু এর সাথে করা যেতে পারে find -path, যদি লক্ষ্য না করা ফাইলগুলি কী ডিরেক্টরি স্তর হতে হবে তা যদি আপনি আপত্তি করেন না। উদাহরণস্বরূপ শেষ হওয়া কোনও পাথ খুঁজে পেতে /e2e/*.js:

$ dirs="$HOME/public $HOME/private"
$ pattern="*/e2e/*.js"
$ find $dirs -path "$pattern"
/home/foo/public/one/two/three/e2e/asdf.js

আমাদের আগের মতো একই কারণে ব্যবহার করতে $HOMEহবে ~, এবং কমান্ড লাইনে $dirsঅকেজো হওয়া দরকার findযাতে এটি বিভক্ত হয়, তবে $patternউদ্ধৃত করা উচিত যাতে এটি শেল দ্বারা দুর্ঘটনাক্রমে প্রসারিত হয় না।

(আমি মনে করি আপনি যদি জিএনইউতে খেলতে পারতেন -maxdepthতবে আপনি যদি যত্নশীল হন তবে অনুসন্ধান কত গভীর হয় তা সীমাবদ্ধ করতে পারেন তবে এটি কিছুটা আলাদা বিষয়))


আপনি কি এক সাথে উত্তর find? লুপটি জটিল হয়ে যাওয়ায় আমি আসলে সেই রুটটিও অন্বেষণ করছি। তবে '-পাথ' নিয়ে আমার সমস্যা হচ্ছে।
জন সিউ 21

টিলড '~' সম্পর্কে আপনার তথ্য হিসাবে আপনাকে Creditণ দেওয়া মূল ইস্যুতে আরও সরাসরি। আমি অন্য উত্তরে চূড়ান্ত স্ক্রিপ্ট এবং ব্যাখ্যা পোস্ট করব। তবে আপনাকে সম্পূর্ণ কৃতিত্ব: ডি
জন সিউ 21

@ জনসুই, হ্যাঁ, অনুসন্ধানটি ব্যবহার করে প্রথমে যা মনে আসে। সঠিক প্রয়োজনের উপর নির্ভর করে এটি ব্যবহারযোগ্যও হতে পারে। (বা আরও ভাল, কিছু ব্যবহারের জন্য।)
ilkkachu

1
@ কেভিনার্প, আমি মনে করি অ্যারেগুলি মূলত কেবল এটির জন্য বোঝানো হয়েছে, এবং হ্যাঁ, "${array[@]}"(উদ্ধৃতি সহ!) নথিবদ্ধ করা হয়েছে ( এখানে এবং এখানে দেখুন ) উপাদানগুলি আরও বিভক্ত না করে আলাদা শব্দ হিসাবে প্রসারিত করতে।
ilkkachu

1
@ সিক্সটিফাইভ, ভাল, গ্লোব নিদর্শনগুলির[abc] একটি স্ট্যান্ডার্ড অংশ , যেমন , আমি মনে করি না যে এগুলি এখানে সমস্ত cover েকে রাখা দরকার । ?
ইলক্কাচু

4

আপনি অনেক ক্ষেত্রে পরে স্ট্রিংয়ের পরিবর্তে এটিকে হিসাবে সংরক্ষণ করতে পারেন এবং আপনি এটি সংজ্ঞায়িত করার সময় গ্লোববিং ঘটতে দিন। আপনার ক্ষেত্রে, উদাহরণস্বরূপ:

k=(~/code/public/*/*.launch)
for i in "${k[@]}"; do

বা পরবর্তী উদাহরণে আপনার evalকিছু স্ট্রিং লাগবে

dirs=(~/code/private/* ~/code/public/*)
for i in "${dirs[@]}"; do
    for j in $exclude; do
        eval "for k in $i/$j; do tmutil addexclusion \"\$k\"; done"
    done
done

1
নোট কিভাবে $excludeওয়াইল্ডকার্ড আছে, আপনি অক্ষম globbing করতে ব্যবহার করার পূর্বে প্রয়োজন চাই বিভক্ত + + উল্লিখিত glob এটিতে অপারেটর এবং জন্য এটিকে পুনরুদ্ধার $i/$jএবং না ব্যবহার evalব্যবহার করতে পারে তবে"$i"/$j
Stéphane Chazelas

আপনারা ও ইল্কচাচু দুজনেই ভাল উত্তর দেন। তবে তার উত্তর বিষয়টি চিহ্নিত করেছে। তাই তাকে কৃতিত্ব।
জন সিউ 21

2

@ ইল্কাচ্ছু উত্তর মূল গ্লোবিংয়ের সমস্যা সমাধান করেছে solved তার পুরো কৃতিত্ব।

V1 থেকে

যাইহোক, excludeওয়াইল্ডকার্ড (*) এর সাথে এবং ছাড়া উভয়ই এন্ট্রি থাকার কারণে এবং সেগুলি সবের মধ্যেই নাও থাকতে পারে, গ্লোব্বিংয়ের পরে অতিরিক্ত চেকিংয়ের প্রয়োজন $i/$j। আমি আমার অনুসন্ধান এখানে ভাগ করে নিচ্ছি।

#!/bin/bash
exclude="
*.launch
.DS_Store
.classpath
.sass-cache
.settings
Thumbs.db
bower_components
build
connect.lock
coverage
dist
e2e/*.js
e2e/*.map
libpeerconnection.log
node_modules
npm-debug.log
testem.log
tmp
typings
"

dirs="
$HOME/code/private/*
$HOME/code/public/*
"

# loop $dirs
for i in $dirs; do
    for j in $exclude ; do
        for k in $i/$j; do
            echo -e "$k"
            if [ -f $k ] || [ -d $k ] ; then
                # Only execute command if dir/file exist
                echo -e "\t^^^ Above file/dir exist! ^^^"
            fi
        done
    done
done

আউটপুট ব্যাখ্যা

পরিস্থিতি ব্যাখ্যা করার জন্য আংশিক আউটপুট নীচে দেওয়া হল।

/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/a.launch
    ^^^ Above file/dir exist! ^^^
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/b.launch
    ^^^ Above file/dir exist! ^^^
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.DS_Store
    ^^^ Above file/dir exist! ^^^

উপরেরগুলি স্ব-বর্ণনামূলক।

/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.classpath
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.sass-cache
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.settings
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/Thumbs.db
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/bower_components
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/build
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/connect.lock
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/coverage
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/dist

উপরের শোটি প্রদর্শিত হবে কারণ বাদ দেওয়া এন্ট্রি ( $j) এর কোনও ওয়াইল্ডকার্ড নেই, $i/$jএকটি সরল স্ট্রিং কনকেন্টেশন হয়ে ওঠে। তবে ফাইল / দির বিদ্যমান নেই।

/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/e2e/*.js
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/e2e/*.map

উপরের $jশিরোনামকে বাদ দেওয়া ( ) এর সাথে ওয়াইল্ডকার্ড রয়েছে তবে এতে কোনও ফাইল / ডিরেক্টরি ম্যাচ নেই, $i/$jকেবলমাত্র মূল স্ট্রিংটি ফিরিয়ে দেবে।

থেকে V2

ভি 2 একক উদ্ধৃতি ব্যবহার করে evalএবং shopt -s nullglobপরিষ্কার ফলাফল পেতে। কোনও ফাইল / দির চূড়ান্ত চেকিংয়ের প্রয়োজন নেই।

#!/bin/bash
exclude='
*.launch
.sass-cache
Thumbs.db
bower_components
build
connect.lock
coverage
dist
e2e/*.js
e2e/*.map
libpeerconnection.log
node_modules
npm-debug.log
testem.log
tmp
typings
'

dirs='
$HOME/code/private/*
$HOME/code/public/*
'

for i in $dirs; do
    for j in $exclude ; do
        shopt -s nullglob
        eval "k=$i/$j"
        for l in $k; do
            echo $l
        done
        shopt -u nullglob
    done
done

একটি সমস্যা হ'ল for j in $exclude, সেই $excludeসম্প্রসারণের সময় গ্লোবগুলি প্রসারিত হতে পারে $exclude(এবং evalসেই বিষয়ে আহ্বান করা সমস্যার জন্য জিজ্ঞাসা করছে)। আপনি এর জন্য সক্ষম globbing চাই চাই for i in $dir, এবং for l in $k, কিন্তু না জন্য for j in $exclude। আপনি set -fআগের একটি আগে এবং অন্যটির set +fজন্য চান। আরও সাধারণভাবে, আপনি এটির আগে আপনার স্প্লিট + গ্লোব অপারেটরটি টিউন করতে চান। যাই হোক না কেন, আপনি এর জন্য বিভাজন + গ্লোব চান না echo $l, সুতরাং $lসেখানে উদ্ধৃত হওয়া উচিত।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস আপনি কি ভি 1 বা ভি 2 তে উল্লেখ করছেন? V2 জন্য, উভয় excludeএবং dirsএকক উদ্ধৃতি (হয় ), so no globbing till eval`।
জন Siu

গ্লোববিং তালিকা প্রসঙ্গে আনউকটেড ভেরিয়েবল প্রসারণের পরে স্থান গ্রহণ করে , যা (একটি ভেরিয়েবলকে উদ্ধৃত করা না হয়) আমরা মাঝে মাঝে বিভাজন + গ্লোব অপারেটর বলে থাকি । স্কেলার ভেরিয়েবলের অ্যাসাইনমেন্টে কোনও গ্লোববিং নেই। foo=*এবং foo='*'একই। তবে echo $fooএবং echo "$foo"তা নয় (যেমন শেলগুলিতে bashএটি zsh, মাছ বা আরসির মতো শেলগুলিতে স্থির করা হয়েছে, উপরের লিঙ্কটিও দেখুন)। এখানে আপনি সেই অপারেটরটি ব্যবহার করতে চান তবে কিছু জায়গায় কেবল বিভক্ত অংশ এবং অন্যদের মধ্যে কেবল গ্লোব অংশ রয়েছে।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস তথ্যের জন্য ধন্যবাদ !!! আমাকে মাঝে মাঝে নিয়ে গেছে তবে আমি এখন উদ্বেগটি বুঝতে পারি। এই খুব মূল্যবান !! ধন্যবাদ!!!
জন সিউ

1

সহ zsh:

exclude='
*.launch
.classpath
.sass-cache
Thumbs.db
...
'

dirs=(
~/code/private/*
~/code/public/*
)

for f ($^dirs/${^${=~exclude}}(N)) {
  echo $f
}

${^array}stringহিসাবে প্রসারিত হয় $array[1]string $array[2]string...$=varভেরিয়েবলের উপরে শব্দের বিভাজন সম্পাদন করা (অন্য কিছু শেল ডিফল্টরূপে করে!), $~varভেরিয়েবলটিতে গ্লোব্বিং করে (অন্য কিছু শাঁসও ডিফল্টরূপে হয় (যখন আপনি সাধারণত সেগুলি চান না, আপনাকে $fউপরের উদ্ধৃতি দিতে হত) অন্যান্য শেল))

(N)এমন একটি গ্লোব কোয়ালিফায়ার যা সেই $^array1/$^array2সম্প্রসারণের ফলে glo সমস্ত গ্লোবগুলির জন্য নালগ্লোব চালু করে । এটি গ্লোবগুলি যখন মেলে না তখন কিছুতেই প্রসারিত করে। এটি একটি অ-গ্লোবকে ~/code/private/foo/Thumbs.dbএকটিতে রূপান্তরিত করতেও ঘটে , যার অর্থ যদি সেই নির্দিষ্টটির অস্তিত্ব না থাকে তবে এটি অন্তর্ভুক্ত নয়।


এটি সত্যিই দুর্দান্ত। আমি পরীক্ষা এবং কাজ করে। তবে একক উদ্ধৃতি ব্যবহার করার সময় zsh নতুন লাইনের প্রতি বেশি সংবেদনশীল বলে মনে হয়। পথ excludeএইসঙ্গে হয় আউটপুট প্রভাবিত হয়।
জন সিউ

@ জনসুই, ওহ হ্যাঁ, আপনি ঠিক বলেছেন এটি স্প্লিট + গ্লোব বলে মনে হচ্ছে এবং $^arrayখালি উপাদানগুলি ফেলে দেওয়া হয়েছে কিনা তা নিশ্চিত করার জন্য অবশ্যই দুটি পৃথক পদক্ষেপে করা উচিত (সম্পাদনা দেখুন) see এটি কিছুটা বাগের মতো দেখায় zsh, আমি তাদের মেলিং তালিকায় বিষয়টি উত্থাপন করব।
স্টাফেন চেজেলাস

আমি বাশের জন্য একটি ভি 2 নিয়ে এসেছি, এটি পরিষ্কার, তবে এখনও আপনার zsh স্ক্রিপ্টের মতো কমপ্যাক্ট নয়, লোল
জন সিউ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.