ফাইলের নামগুলিতে স্পেস থাকলে কীভাবে আমি কমান্ডের আউটপুটটি পার্স করব?


11

যেমন একটি লুপ ব্যবহার করে

for i in `find . -name \*.txt` 

কিছু ফাইলের নাম তাদের মধ্যে স্পেস আছে বিরতি হবে।

এই কৌশল এড়াতে আমি কী কৌশল ব্যবহার করতে পারি?


1
নোট করুন যে ফাইলগুলি তাদের ফাইলের নামতে নতুন লাইন থাকতে পারে। যে কেন আছে find -print0 এবং xargs -0
Daniel Beck

উত্তর:


11

আদর্শভাবে আপনি এটিকে এমনভাবে করবেন না, কারণ একটি শেল স্ক্রিপ্টে সঠিকভাবে ফাইলের নামগুলি বিশ্লেষণ করা সবসময় কঠিন (স্পেসগুলির জন্য এটি ঠিক করুন, আপনাকে এখনও অন্যান্য অন্তর্ভুক্ত করা অক্ষরগুলির সাথে সমস্যাগুলি থাকবে, বিশেষভাবে নতুন লাইন)। এই এমনকি হিসাবে তালিকাভুক্ত করা হয় প্রথম এন্ট্রি BashPitfalls পৃষ্ঠাতে।

যে বলেন, প্রায় আপনি চান কি প্রায় একটি উপায় আছে:

oIFS=$IFS
IFS=$'\n'

find . -name '*.txt' | while read -r i; do
  # use "$i" with whatever you're doing
done

IFS=$oIFS

উদ্ধৃতি মনে রাখবেন $i এটি ব্যবহার করার সময়, স্পেস পরে ব্যাখ্যা অন্যান্য জিনিস এড়াতে। এছাড়াও সেট করতে মনে রাখবেন $IFS এটি ব্যবহার করার পরে ফিরে, কারণ এটি করা না পরে বিদ্বেষপূর্ণ ত্রুটি হতে হবে।

এটি একটি অন্য ক্যাভিট সংযুক্ত আছে: ভিতরে কি ঘটবে while আপনি ব্যবহার করছেন এমন সঠিক শেলের উপর নির্ভর করে লুপটি একটি উপশহলে স্থান নিতে পারে, তাই পরিবর্তনশীল সেটিংস অবিরত থাকতে পারে না। দ্য for লুপ সংস্করণ এড়ানো যে মূল্য কিন্তু যে, এমনকি যদি আপনি আবেদন $IFS সমাধান স্পেস সঙ্গে সমস্যা এড়াতে, আপনি তারপর কষ্ট পেতে হবে find অনেক ফাইল ফিরে।

কিছুক্ষন এটির জন্য যথাযথ সংশোধন শেলের পরিবর্তে পার্ল বা পাইথন যেমন ভাষাতে এটি করা হয়।


1
আমি এই সব এড়ানোর জন্য শুধু পাইথন ব্যবহার ধারণা।
Scott C Wilson

11

ব্যবহার find -print0 এবং এটি পাইপ xargs -0, অথবা আপনার নিজের সামান্য সি প্রোগ্রাম লিখুন এবং আপনার সামান্য সি প্রোগ্রাম এটি পাইপ। এই কি -print0 এবং -0 জন্য উদ্ভাবিত হয়েছিল।

শেল স্ক্রিপ্টগুলি তাদের মধ্যে শূণ্যস্থান সহ ফাইলের নামগুলি পরিচালনা করার সেরা উপায় নয়: আপনি এটি করতে পারেন তবে এটি ক্লান্তি পায়।


আমার মেশিনে কাজ করে ^ টিএম!
mcandre

2

আপনি "অভ্যন্তরীণ ক্ষেত্র বিভাজক" সেট করতে পারেন ( IFS ) লুপ যুক্তি বিভাজন জন্য স্থান চেয়ে অন্য কিছু, যেমন।

ORIGIFS=${IFS}
NL='
'
IFS=${NL}
for i in $(find . -name '*.txt'); do
    IFS=${ORIGIFS}
    #do stuff
done
IFS=${ORIGIFS}

আমি রিসেট IFS এটি ব্যবহার দেখে পরে বেশিরভাগই সুন্দর দেখাচ্ছে কারণ আমি মনে করি। আমি এটি নতুনline সেট করার জন্য কোন সমস্যা দেখা যায় নি, কিন্তু আমি মনে করি এটি "ক্লিনার"।

আরেকটি পদ্ধতি, আপনি আউটপুট সঙ্গে কি করতে চান উপর নির্ভর করে find, হয় সরাসরি ব্যবহার করা হয় -exec সঙ্গে find কমান্ড, বা ব্যবহার -print0 এবং এটি মধ্যে পাইপ xargs -0। প্রথম ক্ষেত্রে find escaping ফাইল নাম যত্ন নেয়। মধ্যে -print0 মামলা, find একটি নল বিভাজক সঙ্গে তার আউটপুট প্রিন্ট, এবং তারপর xargs এই উপর বিভক্ত। যেহেতু কোনও ফাইলের নামটি সেই অক্ষরটি ধারণ করতে পারে না (যা আমি জানি), এটি সর্বদা নিরাপদ। এটি বেশিরভাগ ক্ষেত্রে সহজেই দরকারী; এবং সাধারণত একটি পূর্ণ জন্য একটি মহান বিকল্প নয় for লুপ.


1

ব্যবহার find -print0 সঙ্গে xargs -0

ব্যবহার find -print0 সংযুক্ত xargs -0 সম্পূর্ণ আইনি ফাইল নামের বিরুদ্ধে শক্তসমর্থ, এবং উপলব্ধ সবচেয়ে এক্সটেনসিবল পদ্ধতির এক। উদাহরণস্বরূপ, আপনি বর্তমান ডিরেক্টরির মধ্যে প্রতিটি পিডিএফ ফাইল একটি তালিকা চেয়েছিলেন বলে। আপনি লিখতে পারে

$ find . -iname '*.pdf' -print0 | xargs -0 -n 1 echo

এই প্রতিটি পিডিএফ পাবেন (মাধ্যমে -iname '*.pdf' ) বর্তমান ডিরেক্টরি ( . ) এবং কোন উপ-ডিরেক্টরি, এবং তাদের প্রতিটি একটি যুক্তি হিসাবে পাস echo কমান্ড। কারণ আমরা নির্দিষ্ট -n 1 বিকল্প, xargs একটি সময়ে শুধুমাত্র এক যুক্তি পাস হবে echo। আমরা যে বিকল্প omitted ছিল, xargs সম্ভব হিসাবে অনেক পাস হবে echo। (আপনি করতে পারেন echo short input | xargs --show-limits একটি কমান্ড লাইনে কত বাইট অনুমতি দেওয়া হয় তা দেখতে।)

কি করে xargs ঠিক আছে?

আমরা পরিষ্কারভাবে প্রভাব দেখতে পারেন xargs তার ইনপুট আছে - এবং প্রভাব -n বিশেষ করে - একটি স্ক্রিপ্ট ব্যবহার করে যা তার আর্গুমেন্ট echos তুলনায় আরো সুনির্দিষ্ট পদ্ধতিতে echo

$ cat > echoArgs.sh <<'EOF'
#!/bin/bash
echo "Number of arguments: $#"

[[ $# -eq 0 ]] && exit

for i in $(seq 1 $#); do
    echo "Arg $i: <$1>"
    shift
done
EOF

$ find . -iname '*.pdf' -print0 | xargs -0 ./echoArgs.sh
$ find . -iname '*.pdf' -print0 | xargs -0 -n 1 ./echoArgs.sh

এটা পুরোপুরি ভাল স্পেস এবং newlines পরিচালনা করে যে নোট,

$ touch 'A space-age
new line of vending machines.pdf'
$ find . -iname '*space*' -print0 | xargs -0 -n 1 ./echoArgs.sh

যা নিম্নলিখিত সাধারণ সমাধানগুলির সাথে বিশেষ করে বিরক্তিকর হবে:

chmod +x ./echoArgs.sh
for file in $(ls *spacey*); do
  ./echoArgs.sh "$file"
done
নোট

1

আমি সঙ্গে অসম্মতি bash বুশ, কারণ bash* নিক্স টুল সেট বরাবর, ফাইলগুলি পরিচালনা করার ক্ষেত্রে বেশ দক্ষ (যার নামগুলি হোয়াইট স্পেস অন্তর্ভুক্ত করেছে) সহ।

আসলে, find কোন ফাইলগুলি প্রক্রিয়া করতে হবে তা চয়ন করার জন্য আপনাকে জরিমানা শস্য নিয়ন্ত্রণ দেয় ... বিশৃঙ্খলার দিকে, আপনাকে কেবলমাত্র বুঝতে হবে যে আপনাকে অবশ্যই স্ট্রিং করতে হবে bash words; সাধারণত "ডাবল কোটস" ব্যবহার করে, বা আইএফএস ব্যবহার করার মতো কিছু অন্যান্য প্রক্রিয়া বা খুঁজে বের করে {}

উল্লেখ্য যে বেশিরভাগ / অনেক ক্ষেত্রে আপনাকে আইএফএস সেট এবং রিসেট করতে হবে না; নীচের উদাহরণে দেখানো হিসাবে স্থানীয়ভাবে আইএফএস ব্যবহার করুন। সব তিনটি হ্যান্ডেল হোয়াইটস্পেস জরিমানা। এছাড়াও আপনি একটি "আদর্শ" লুপ গঠন প্রয়োজন হয় না, কারণ এর এটি \; হয় কার্যকরভাবে একটি লুপ; শুধু আপনার লুপ লজিককে একটি ব্যাশ ফাংশনে রাখুন (যদি আপনি একটি আদর্শ সরঞ্জাম কল না করেন)।

IFS=$'\n' find ~/ -name '*.txt' -exec  function-or-util {} \;  

এবং, আরো দুটি উদাহরণ

IFS=$'\n' find ~/ -name '*.txt' -exec  printf 'Hello %s\n' {} \;  
IFS=$'\n' find ~/ -name '*.txt' -exec  echo {} \+ |sed 's/home//'  

'খুঁজতে also allows you to pass multiple filenames as args to you script ..(if it suits your need: use + + instead \; `)


1
উভয় দৃষ্টিকোণ কিছু বৈধতা আছে। যখন আমি কেবল আমার নিজের ফাইলগুলিতে কাজ করছিলাম, তখন আমি কেবল এটি ব্যবহার করতে এবং এটি সম্পর্কে চিন্তিত হব না কারণ আমার ফাইলগুলিতে তাদের নামগুলিতে স্থান (অথবা ক্যারেজ ফেরত!) নেই। কিন্তু যখন আপনি অন্য লোকেদের ফাইলগুলির সাথে কাজ শুরু করেন, তখন আপনাকে আরো জোরালো কৌশলগুলি ব্যবহার করতে হবে।
Scott C Wilson
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.