উপাদানগুলিতে ফাঁক দিয়ে অ্যারে বাশ করুন


150

আমি আমার ক্যামেরা থেকে ফাইলনামগুলির ব্যাশে একটি অ্যারে তৈরি করার চেষ্টা করছি:

FILES=(2011-09-04 21.43.02.jpg
2011-09-05 10.23.14.jpg
2011-09-09 12.31.16.jpg
2011-09-11 08.43.12.jpg)

আপনি দেখতে পাচ্ছেন, প্রতিটি ফাইলের নামের মাঝখানে একটি জায়গা রয়েছে।

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

আমি যখন অ্যারে উপাদানগুলিতে অ্যাক্সেস করার চেষ্টা করি তখন এটি স্থানটিকে এলিমেন্টিলেমিটার হিসাবে বিবেচনা করতে থাকে।

কিভাবে আমি নামের ভিতরে একটি স্থান সহ ফাইলের নামগুলি সঠিকভাবে ক্যাপচার করতে পারি?


আপনি কি ফাইলগুলিকে পুরানো ধাঁচে যুক্ত করার চেষ্টা করেছেন? পছন্দ FILES[0] = ...? (সম্পাদনা করুন: আমি সবেমাত্র করেছি; কাজ করে না Interest আকর্ষণীয়)।
ড্যান ফেগো


এখানে থাকা সমস্ত উত্তর আমার জন্য সাইগউইন ব্যবহার করে ভেঙে যায়। ফাইলের নাম, পিরিয়ডে ফাঁকা স্থান থাকলে এটি অদ্ভুত কাজ করে। আমি যে সমস্ত উপাদানগুলির সাথে কাজ করতে চাইছি তার একটি টেক্সট ফাইলের তালিকাতে একটি "অ্যারে" তৈরি করে এবং ফাইলে লাইনগুলি নিয়ে পুনরাবৃত্তি করে এটির চারপাশে কাজ করি: বিন্যাসে কমান্ডটি ঘিরে বিন্যাসটি বিন্যাস করা হচ্ছে: IFS = ""; অ্যারে = ( find . -maxdepth 1 -type f -iname \*.$1 -printf '%f\n'); উপাদানটির জন্য $ {অ্যারে [@]}; প্রতিধ্বনি $ উপাদান করুন; সম্পন্ন
অ্যালেক্স হল

উত্তর:


121

আমি মনে করি আপনি কীভাবে উপাদানগুলিতে অ্যাক্সেস করছেন তাতে সমস্যাটি আংশিক হতে পারে। আমি যদি সাধারণ কাজটি করি তবে আমি আপনার for elem in $FILESমতো একই সমস্যাটিও অনুভব করব। যাইহোক, যদি আমি অ্যারে এর সূচকগুলির মাধ্যমে অ্যাক্সেস করি তবে এর মতো, আমি উপাদানগুলি সংখ্যায়িতভাবে বা পলায়নকারীদের সাথে যুক্ত করলে এটি কাজ করে:

for ((i = 0; i < ${#FILES[@]}; i++))
do
    echo "${FILES[$i]}"
done

এই ঘোষণার যে কোনও $FILESকাজ করা উচিত:

FILES=(2011-09-04\ 21.43.02.jpg
2011-09-05\ 10.23.14.jpg
2011-09-09\ 12.31.16.jpg
2011-09-11\ 08.43.12.jpg)

অথবা

FILES=("2011-09-04 21.43.02.jpg"
"2011-09-05 10.23.14.jpg"
"2011-09-09 12.31.16.jpg"
"2011-09-11 08.43.12.jpg")

অথবা

FILES[0]="2011-09-04 21.43.02.jpg"
FILES[1]="2011-09-05 10.23.14.jpg"
FILES[2]="2011-09-09 12.31.16.jpg"
FILES[3]="2011-09-11 08.43.12.jpg"

6
মনে রাখবেন যে আপনি অ্যারে উপাদানগুলি (উদাঃ echo "${FILES[$i]}") ব্যবহার করার সময় ডাবল-কোট ব্যবহার করা উচিত । এটি কোনও বিষয় নয় echo, তবে এটি ফাইল-নাম হিসাবে এটি যে কোনও ক্ষেত্রে এটি ব্যবহার করবে।
গর্ডন ডেভিসন

26
আপনি যখন উপাদানগুলির সাথে লুপ করতে পারেন তখন সূচীগুলিতে লুপ করা প্রয়োজন হয় না for f in "${FILES[@]}"
মার্ক এডগার

10
অ্যারে সদস্যদের ফাঁকা রাখার পরে @ মার্কএডগার আমি $ {ফাইলগুলি [@] f এ f নিয়ে সমস্যা অনুভব করছি । মনে হচ্ছে পুরো অ্যারেটি পুনরায় ব্যাখ্যা করা হয়েছে, শূন্যস্থানগুলি আপনার বিদ্যমান সদস্যদের দুটি বা ততোধিক উপাদানগুলিতে স্পিট করে। মনে হচ্ছে "" খুব গুরুত্বপূর্ণ
মাইকেল শ

1
তীক্ষ্ণ ( #) চিহ্নটি for ((i = 0; i < ${#FILES[@]}; i++))বিবৃতিতে কী করে?
মিশাল ভাইশিয়ান

4
আমি এর উত্তর ছয় বছর আগে দিয়েছি তবে আমি বিশ্বাস করি এটি অ্যারে ফাইলের উপাদানগুলির সংখ্যা গণনা করা
ড্যান ফেগো

91

অ্যারের আইটেমগুলি যেভাবে আপনি অ্যাক্সেস করেন তাতে অবশ্যই কিছু সমস্যা আছে। এটি কিভাবে সম্পন্ন হয়েছে তা এখানে:

for elem in "${files[@]}"
...

থেকে ব্যাশ র manpage :

অ্যারের কোনও উপাদান $ {নাম [সাবস্ক্রিপ্ট] using ব্যবহার করে রেফারেন্স করা যেতে পারে} ... সাবস্ক্রিপ্ট যদি @ বা * হয় তবে শব্দটি নামের সমস্ত সদস্যের কাছে প্রসারিত হয়। এই সাবস্ক্রিপ্টগুলি কেবল তখনই পৃথক হয় যখন শব্দটি ডাবল উদ্ধৃতিতে উপস্থিত হয়। যদি শব্দটি ডাবল-কোট করা থাকে তবে $ {নাম [*]} আইএফএস বিশেষ ভেরিয়েবলের প্রথম অক্ষর দ্বারা পৃথক পৃথক প্রতিটি অ্যারে সদস্যের মান সহ একটি শব্দে প্রসারিত হয় এবং $ {নাম [@] of এর প্রতিটি উপাদানকে প্রসারিত করে একটি পৃথক শব্দ নাম

অবশ্যই, কোনও একক সদস্যের অ্যাক্সেস করার সময় আপনার ডাবল উক্তি ব্যবহার করা উচিত

cp "${files[0]}" /tmp

3
এই গুচ্ছটির মধ্যে সবচেয়ে পরিষ্কার, সবচেয়ে মার্জিত সমাধান, যদিও অ্যারেতে সংজ্ঞায়িত প্রতিটি উপাদান উদ্ধৃত করা উচিত তা পুনরাবৃত্তি করা উচিত।
ম্যাভেরিক

ড্যান ফেগোয়ের উত্তর কার্যকর হলেও, উপাদানগুলির মধ্যে স্পেসগুলি হ্যান্ডেল করার এটি আরও মুর্তিযুক্ত উপায়।
ড্যানিয়েল জাং

3
অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজ থেকে আসা, সেই উদ্ধৃতি থেকে পরিভাষাটি বোঝা সত্যিই শক্ত। প্লাস সিনট্যাক্স বিস্মিত হয়। আপনি যদি আরও কিছুটা intoুকতে পারতেন তবে আমি অত্যন্ত কৃতজ্ঞ হব? বিশেষতexpands to a single word with the value of each array member separated by the first character of the IFS special variable
CL22

1
হ্যাঁ, দ্বিগুণ উদ্ধৃতিগুলি এটি সমাধান করছে তা সম্মত হন এবং এটি অন্যান্য সমাধানগুলির চেয়ে ভাল। আরও ব্যাখ্যা করতে - বেশিরভাগ অন্যান্যর মধ্যে কেবল ডাবল উদ্ধৃতি নেই। আপনি সঠিকটি পেয়েছেন: for elem in "${files[@]}"যদিও তাদের রয়েছে for elem in ${files[@]}- তাই স্পেসগুলি প্রসারকে বিভ্রান্ত করে এবং পৃথক শব্দের উপর চালানোর চেষ্টা করে।
26:57

এটি ম্যাকোস 10.14.4-এ আমার পক্ষে কাজ করে না, যা "জিএনইউ ব্যাশ, সংস্করণ 3.2.57 (1) -রিলেজ (x86_64-আপেল-ডারউইন 18)" ব্যবহার করে। বাশ এর পুরানো সংস্করণে একটি বাগ হতে পারে?
মার্ক রিবাউ

43

উপাদান ডিলিমিটার হিসাবে স্থান থামাতে আপনার আইএফএস ব্যবহার করতে হবে।

FILES=("2011-09-04 21.43.02.jpg"
       "2011-09-05 10.23.14.jpg"
       "2011-09-09 12.31.16.jpg"
       "2011-09-11 08.43.12.jpg")
IFS=""
for jpg in ${FILES[*]}
do
    echo "${jpg}"
done

আপনি যদি ভিত্তিতে পৃথক করতে চান। তারপরে কেবল আইএফএস = "করুন।" আশা করি এটি আপনাকে সহায়তা করবে :)


3
অ্যারে অ্যাসাইনমেন্টের আগে আমাকে আইএফএস = "" এ স্থানান্তরিত করতে হয়েছিল তবে এটি সঠিক উত্তর।
ছিনিয়ে নিন

তথ্য পার্স করার জন্য আমি বেশ কয়েকটি অ্যারে ব্যবহার করছি এবং আমি কেবল তার মধ্যে একটিতে আইএফএস = "" কাজ করার প্রভাব ফেলব। আমি একবার আইএফএস = "" ব্যবহার করলে অন্যান্য সমস্ত অ্যারে সেই অনুযায়ী পার্সিং বন্ধ করে দেয়। এই সম্পর্কে কোন ইঙ্গিত?
পাওলো পেদ্রোসো

পাওলো, এখানে আরও একটি উত্তর দেখুন যা আপনার ক্ষেত্রে ভাল হতে পারে: stackoverflow.com/a/9089186/1041319 । আইএফএস = "" চেষ্টা করে দেখেননি এবং দেখে মনে হচ্ছে এটি এটিকে মার্জিতভাবে সমাধান করে - তবে আপনার উদাহরণটি দেখায় যে কেন কিছু কিছু ক্ষেত্রে সমস্যা হতে পারে। আইএফএস = "" একক লাইনে সেট করা সম্ভব হতে পারে তবে এটি এখনও অন্য সমাধানের চেয়ে আরও বিভ্রান্তিকর হতে পারে।
আর্ট্জ

এটি আমার জন্য বাশ নিয়েও কাজ করেছিল। ধন্যবাদ @ খুশনীত আমি আধ ঘন্টা এটি সন্ধান
করছিলাম

দুর্দান্ত, কেবল এই পৃষ্ঠায় উত্তরটি কাজ করে। কিন্তু IFS="" অ্যারে নির্মাণের আগে আমাকেও সরানো হয়েছিল ।
pkamb

13

আমি অন্যদের সাথে একমত হই যে সম্ভবত আপনি যে সমস্যাগুলির উপাদানগুলিতে অ্যাক্সেস করছেন সেটি সম্ভবত likely অ্যারে অ্যাসাইনমেন্টে ফাইলের নাম উদ্ধৃত করা সঠিক:

FILES=(
  "2011-09-04 21.43.02.jpg"
  "2011-09-05 10.23.14.jpg"
  "2011-09-09 12.31.16.jpg"
  "2011-09-11 08.43.12.jpg"
)

for f in "${FILES[@]}"
do
  echo "$f"
done

ফর্মের যে কোনও অ্যারের আশেপাশে ডাবল উদ্ধৃতি ব্যবহার করে "${FILES[@]}"অ্যারে উপাদানকে প্রতি শব্দের মধ্যে অ্যারে বিভক্ত করা হয়। এটি এর বাইরে কোনও শব্দ বিভাজন করে না।

ব্যবহার "${FILES[*]}"একটি বিশেষ অর্থ আছে, কিন্তু এটা যোগদান করে $ IFS প্রথম অক্ষর, ফলে সঙ্গে অ্যারে উপাদানের এক শব্দ, যা সম্ভবত নয় কি আপনি চান।

খালি ${array[@]}বা ${array[*]}বিষয়গুলি ব্যবহার করে শব্দটির বিভাজনে আরও বিস্তৃত হওয়ার ফলাফল রয়েছে, সুতরাং আপনার $IFSঅ্যারে উপাদানগুলির প্রতি এক শব্দের পরিবর্তে স্পেসে (এবং অন্য কোনও কিছু ) শব্দের বিভক্ত হবে ।

লুপের জন্য সি-স্টাইল ব্যবহার করাও জরিমানা এবং যদি আপনি এটি পরিষ্কার করে না থাকেন তবে শব্দ বিভাজন সম্পর্কে চিন্তিত হওয়া এড়ানো হবে:

for (( i = 0; i < ${#FILES[@]}; i++ ))
do
  echo "${FILES[$i]}"
done

3

পালানোর কাজ

#!/bin/bash

FILES=(2011-09-04\ 21.43.02.jpg
2011-09-05\ 10.23.14.jpg
2011-09-09\ 12.31.16.jpg
2011-09-11\ 08.43.12.jpg)

echo ${FILES[0]}
echo ${FILES[1]}
echo ${FILES[2]}
echo ${FILES[3]}

আউটপুট:

$ ./test.sh
2011-09-04 21.43.02.jpg
2011-09-05 10.23.14.jpg
2011-09-09 12.31.16.jpg
2011-09-11 08.43.12.jpg

স্ট্রিং উদ্ধৃতি একই আউটপুট উত্পাদন করে।


3

আপনার যদি আপনার অ্যারেটি এমনভাবে থাকে: #! / বিন / বাশ

Unix[0]='Debian'
Unix[1]="Red Hat"
Unix[2]='Ubuntu'
Unix[3]='Suse'

for i in $(echo ${Unix[@]});
    do echo $i;
done

আপনি পাবেন:

Debian
Red
Hat
Ubuntu
Suse

আমি জানি না কেন তবে লুপটি ফাঁকা স্থানগুলি ভেঙে দেয় এবং এটিকে পৃথক আইটেম হিসাবে রাখে, এমনকি আপনি এটিকে উদ্ধৃতি দিয়ে ঘিরে রাখেন।

এটি পেতে, অ্যারেতে উপাদানগুলি কল করার পরিবর্তে, আপনি সূচিগুলিকে কল করেন, যা উদ্ধৃতিতে মোড়ানো পুরো স্ট্রিং থ্যাটস নেয়। এটা অবশ্যই উদ্ধৃতি আবৃত করা উচিত!

#!/bin/bash

Unix[0]='Debian'
Unix[1]='Red Hat'
Unix[2]='Ubuntu'
Unix[3]='Suse'

for i in $(echo ${!Unix[@]});
    do echo ${Unix[$i]};
done

তারপরে আপনি পাবেন:

Debian
Red Hat
Ubuntu
Suse

2

মূল প্রশ্নের উদ্ধৃতি / পলায়ন সমস্যার সঠিক উত্তর নয় তবে সম্ভবত এমন কিছু যা আসলে অপের জন্য আরও কার্যকর হতে পারে:

unset FILES
for f in 2011-*.jpg; do FILES+=("$f"); done
echo "${FILES[@]}"

অবশ্যই অবশ্যই অভিব্যক্তিটি নির্দিষ্ট প্রয়োজনীয়তার জন্য গ্রহণ করতে হবে (উদাহরণস্বরূপ *.jpgসকলের 2001-09-11*.jpgজন্য বা কেবলমাত্র একটি নির্দিষ্ট দিনের ছবির জন্য)।


0

অন্য সমাধানটি "যখন" লুপ পরিবর্তে "" জন্য "লুপ ব্যবহার করছে:

index=0
while [ ${index} -lt ${#Array[@]} ]
  do
     echo ${Array[${index}]}
     index=$(( $index + 1 ))
  done

0

যদি আপনি ব্যবহারে আটকে না bashথাকেন তবে ফাইলের নামের ফাঁকে ফাঁকে বিভিন্ন হ্যান্ডলিং করা মাছের শেলের অন্যতম সুবিধা । একটি ডিরেক্টরি বিবেচনা করুন যাতে দুটি ফাইল রয়েছে: "একটি বি.এস.এক.এক্স.টি." এবং "বি সি.টি. টেক্সট"। এখানে অন্য কমান্ড থেকে উত্পন্ন ফাইলগুলির তালিকা প্রক্রিয়াকরণের একটি যুক্তিসঙ্গত অনুমান bash, তবে আপনার অভিজ্ঞ ফাইলের নাম ফাঁকা হওয়ার কারণে এটি ব্যর্থ হয়:

# bash
$ for f in $(ls *.txt); { echo $f; }
a
b.txt
b
c.txt

এর সাথে fishবাক্য গঠনটি প্রায় অভিন্ন, তবে ফলাফলটি আপনি প্রত্যাশা করতেন:

# fish
for f in (ls *.txt); echo $f; end
a b.txt
b c.txt

এটি ভিন্নভাবে কাজ করে কারণ মাছগুলি নতুন লাইনে কমান্ডের আউটপুট বিভক্ত করে, ফাঁকা স্থান নয়।

আপনার যদি এমন কোনও মামলা থাকে যেখানে আপনি নতুন লাইনের পরিবর্তে স্পেসে বিভক্ত করতে চান তবে তার জন্য fishখুব পঠনযোগ্য বাক্য গঠন রয়েছে:

for f in (ls *.txt | string split " "); echo $f; end

0

আমি হয়ে গেলে আইএফএস মান এবং রোলব্যাক পুনরায় সেট করতে ব্যবহার করি ।

# backup IFS value
O_IFS=$IFS

# reset IFS value
IFS=""

FILES=(
"2011-09-04 21.43.02.jpg"
"2011-09-05 10.23.14.jpg"
"2011-09-09 12.31.16.jpg"
"2011-09-11 08.43.12.jpg"
)

for file in ${FILES[@]}; do
    echo ${file}
done

# rollback IFS value
IFS=${O_IFS}

লুপ থেকে সম্ভাব্য আউটপুট:

2011-09-04 21.43.02.jpg

2011-09-05 10.23.14.jpg

2011-09-09 12.31.16.jpg

2011-09-11 08.43.12.jpg

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