ফাইন্ড-এক্সেক কলটিতে ব্যবহারকারী নির্ধারিত ফাংশন সম্পাদন করা হচ্ছে


25

আমি সোলারিস 10 এ আছি এবং আমি নিম্নলিখিতটি ksh (88), বাশ (3.00) এবং zsh (4.2.1) দিয়ে পরীক্ষা করেছি।

নিম্নলিখিত কোডটি কোনও ফল দেয় না:

function foo {
    echo "Hello World"
}

find somedir -exec foo \;

অনুসন্ধানটি বেশ কয়েকটি ফাইলের সাথে মেলে না (যেমন প্রতিস্থাপনের -exec ...মাধ্যমে দেখানো হয়েছে -print), এবং findকলটি বাইরে থেকে ডাকলে ফাংশনটি পুরোপুরি কাজ করে ।

man findপৃষ্ঠাটি সম্পর্কে যা বলে তা এখানে -exec:

 এক্সেক্স কমান্ড সত্য যদি এক্সিকিউটেড কমান্ডটি a প্রদান করে
                     প্রস্থান স্থিতি হিসাবে শূন্য মান। শেষে
                     কমান্ড অবশ্যই একটি পালানো দ্বারা বিরামচিহ্ন করা উচিত
                     সেমিকোলন (;)। একটি কমান্ড আর্গুমেন্ট {}
                     বর্তমান পথের নাম দ্বারা প্রতিস্থাপিত। যদি
                     এক্সেক-এর শেষ যুক্তিটি {is এবং আপনি
                     সেমিকোলন (;) এর পরিবর্তে + নির্দিষ্ট করুন,
                     কমান্ডটি কয়েকবার ডাকা হয় with
                     path path পথের গ্রুপগুলির দ্বারা প্রতিস্থাপিত। যদি
                     কমান্ডের যে কোনও প্রার্থনা প্রত্যাবর্তন করে a
                     প্রস্থান স্থিতি হিসাবে শূন্য-মান, সন্ধান করুন
                     একটি শূন্য-বহির্গমন স্থিতি ফেরত দেয়।

আমি সম্ভবত এই জাতীয় কিছু করে পালাতে পারি:

for f in $(find somedir); do
    foo
done

তবে আমি ফিল্ড বিভাজক সমস্যাগুলি মোকাবেলা করতে ভয় পাচ্ছি।

কোনও কল থেকে কোনও শেল ফাংশন (একই স্ক্রিপ্টে সংজ্ঞায়িত করা যাক, স্কোপিংয়ের সমস্যাগুলি নিয়ে বিরক্ত না করা) find ... -exec ...কল করা কি সম্ভব?

আমি উভয় সঙ্গে এটা চেষ্টা /usr/bin/findএবং /bin/findএবং একই ফলাফল পেয়েছেন।


আপনি ফাংশনটি ঘোষণার পরে কি রফতানি করার চেষ্টা করেছিলেন? export -f foo
h3rrmiller

2
আপনাকে ফাংশনটিকে একটি বাহ্যিক স্ক্রিপ্ট তৈরি করতে হবে এবং এটিকে প্রবেশ করতে হবে PATH। বিকল্পভাবে, ব্যবহার sh -c '...'এবং উভয় ...বিট মধ্যে ফাংশন সংজ্ঞায়িত এবং চালানো । এটি ফাংশন এবং স্ক্রিপ্টগুলির মধ্যে পার্থক্য বুঝতে সহায়তা করতে পারে ।
jw013

উত্তর:


27

functionএকটি শেলের স্থানীয়, সুতরাং আপনার find -execশেলটি স্প্যান করতে হবে এবং এটি ব্যবহারের পক্ষে সক্ষম হওয়ার আগে সেই শেলটিতে সেই ফাংশনটি সংজ্ঞায়িত করতে হবে। কিছুটা এইরকম:

find ... -exec ksh -c '
  function foo {
    echo blan: "$@"
  }
  foo "$@"' ksh {} +

bashএকজনকে পরিবেশের মাধ্যমে ফাংশন রফতানি করার অনুমতি দেয় export -f, যাতে আপনি (বাশিতে) করতে পারেন:

foo() { ...; }
export -f foo
find ... -exec bash -c 'foo "$@"' bash {} +

ksh88হয়েছে typeset -fxরপ্তানি ফাংশন (পরিবেশ মাধ্যমে নয়), কিন্তু যে শুধুমাত্র সে-ঠুং কম দ্বারা সঞ্চালিত স্ক্রিপ্ট ব্যবহার করতে পারে ksh, তাই না ksh -c

অন্য বিকল্পটি হ'ল:

find ... -exec ksh -c "
  $(typeset -f foo)"'
  foo "$@"' ksh {} +

এটি, ইনলাইন স্ক্রিপ্টের ভিতরে ফাংশনটির typeset -fসংজ্ঞা ডাম্প করতে ব্যবহার করুন foo। মনে রাখবেন যে যদি fooঅন্যান্য ফাংশন ব্যবহার করে তবে আপনার সেগুলিও ফেলে দিতে হবে।


2
কেন আপনি দুটি ঘটনার আছে ব্যাখ্যা করতে পারবেন kshবা bashমধ্যে -execকমান্ড? আমি প্রথম বুঝতে পারি, তবে দ্বিতীয় ঘটনাটি নয়।
ড্যানিয়েল কুলম্যান 8

6
@danielkullmann ইন bash -c 'some-code' a b c, $0হয় a, $1হয় b..., তাই যদি আপনি চান $@হতে a, b, cআপনি আগে কিছু সন্নিবেশ করতে হবে। কারণ $0ত্রুটি বার্তাগুলি প্রদর্শন করার সময়ও ব্যবহৃত হয়, শেলটির নাম ব্যবহার করা ভাল ধারণা বা সেই প্রসঙ্গে উপলব্ধি করা কিছু।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস, এইরকম সুন্দর উত্তরের জন্য আপনাকে ধন্যবাদ।
ব্যবহারকারী 9102d82

5

এটি সর্বদা প্রযোজ্য নয়, তবে এটি যখন হয় তখন এটি একটি সহজ সমাধান। globstarবিকল্পটি সেট করুন ( set -o globstarksh93 এ, shopt -s globstarব্যাশ ≥4 এ; এটি zsh এ ডিফল্টরূপে চালু আছে)। তারপরে **/বর্তমান ডিরেক্টরি এবং এর উপ-ডিরেক্টরিগুলি পুনরাবৃত্তভাবে মেলতে ব্যবহার করুন।

উদাহরণস্বরূপ, পরিবর্তে find . -name '*.txt' -exec somecommand {} \;, আপনি চালাতে পারেন

for x in **/*.txt; do somecommand "$x"; done

পরিবর্তে find . -type d -exec somecommand {} \;, আপনি চালাতে পারেন

for d in **/*/; do somecommand "$d"; done

পরিবর্তে find . -newer somefile -exec somecommand {} \;, আপনি চালাতে পারেন

for x in **/*; do
  [[ $x -nt somefile ]] || continue
  somecommand "$x"
done

কখন আপনার **/পক্ষে কাজ করে না (কারণ আপনার শেলটিতে এটি নেই, বা findআপনার কোনও শেল অ্যানালগ নেই এমন বিকল্পের প্রয়োজন আছে) যুক্তির মাধ্যমে কার্যটি সংজ্ঞায়িত করুনfind -exec


আমি ব্যবহার করছি globstarএমন ksh ( ksh88) সংস্করণে আমি কোনও বিকল্প খুঁজে পাচ্ছি না।
রাহমু

@ রহমু আসলে, এটি ksh93 এ নতুন new সোলারিস 10 এর কোথাও ksh93 নেই?
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন'

এই ব্লগ পোস্ট অনুসারে ksh93 সোলারিস 11 এ বর্ন শেল এবং ksh88 উভয়কে প্রতিস্থাপনের জন্য চালু করা হয়েছে ...
রাহমু

@rahmu। সোলারিসের কিছু সময়ের জন্য ksh93 ছিল dtksh(কিছু এক্স 11 এক্সটেনশন সহ ksh93), তবে একটি পুরানো সংস্করণ এবং সম্ভবত একটি alচ্ছিক প্যাকেজের অংশ যেখানে সিডিই optionচ্ছিক।
স্টাফেন চেজেলাস

এটি লক্ষ করা উচিত যে পুনরাবৃত্ত গ্লোববিং এর থেকে পৃথক findহয় যে এটি ডটফাইলগুলি বাদ দেয় এবং ডটডিয়ারগুলিতে নামবে না এবং এটি ফাইল তালিকাটি সাজায় (উভয়ই গ্লোব্বিং কোয়ালিফায়ারের মাধ্যমে zsh এ ঠিকানা হতে পারে)। এর **/*বিপরীতে ./**/*, ফাইলের নামগুলি শুরু হতে পারে -
স্টাফেন চেজেলাস

4

ডেলিমিটার হিসাবে \ 0 ব্যবহার করুন এবং বর্তমান প্রক্রিয়ায় ফাইল নামগুলি একটি স্পাড কমান্ড থেকে পড়ুন, যেমন:

foo() {
  printf "Hello {%s}\n" "$1"
}

while read -d '' filename; do
  foo "${filename}" </dev/null
done < <(find . -maxdepth 2 -type f -print0)

এখানে কি হচ্ছে:

  • read -d '' পরের \ 0 বাইট অবধি পঠন করে, তাই আপনাকে ফাইলের নামগুলিতে অদ্ভুত অক্ষরগুলি নিয়ে চিন্তা করতে হবে না।
  • একইভাবে, -print0প্রতিটি উত্পন্ন ফাইলের নাম \ n এর পরিবর্তে ate 0 ব্যবহার করে।
  • cmd2 < <(cmd1)হিসাবে একই cmd1 | cmd2ছাড়া CMD2 প্রধান শেল চালানোর এবং একটি subshell।
  • ভুল থেকে কলটি /dev/nullপাইপ থেকে দুর্ঘটনাক্রমে না পড়ে তা নিশ্চিত করার জন্য কল থেকে পুনঃনির্দেশিত করা হয়েছে।
  • $filename উদ্ধৃত করা হয়েছে যাতে শেলটি সাদা ফাইল থাকা কোনও ফাইলের নাম বিভক্ত করার চেষ্টা করে না।

এখন, read -dএবং <(...)zsh, bash এবং ksh 93u এ আছেন তবে আমি আগের ksh সংস্করণ সম্পর্কে নিশ্চিত নই।


4

যদি আপনি কোনও পূর্ব-সংজ্ঞায়িত শেল ফাংশন ব্যবহার করে আপনার স্ক্রিপ্ট থেকে তৈরি একটি শিশু প্রক্রিয়া চান তবে এটির সাথে রফতানি করতে হবে export -f <function>

দ্রষ্টব্য: export -fবাশ নির্দিষ্ট

যেহেতু কেবল একটি শেল শেল ফাংশন চালাতে পারে:

find / -exec /bin/bash -c 'function "$1"' bash {} \;

সম্পাদনা: মূলত আপনার স্ক্রিপ্টটি এর অনুরূপ হওয়া উচিত:

#!/bin/bash
function foo() { do something; }
export -f foo
find somedir -exec /bin/bash -c 'foo "$0"' {} \;

1
export -fএটি একটি সিনট্যাক্স ত্রুটি এবং kshএতে স্ক্রিনে ফাংশন সংজ্ঞাটি মুদ্রণ করে zsh। সব মিলিয়ে ksh, zshএবং bash, এটি সমস্যার সমাধান করে না।
রাহমু

1
find / -exec /bin/bash -c 'function' \;
h3rrmiller

এখন এটি কাজ করে তবে কেবল সাথে bash। ধন্যবাদ!
রাহমু

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