"এমভি: আর্গুমেন্টের তালিকা খুব দীর্ঘ" সমাধান করা হচ্ছে?


64

আমার এক মিলিয়নেরও বেশি ফাইল সহ একটি ফোল্ডার রয়েছে যার জন্য বাছাই করা দরকার, তবে আমি সত্যিই কিছু করতে পারি না কারণ mvএই বার্তাটি সর্বদা আউটপুট দেয় I

-bash: /bin/mv: Argument list too long

এক্সটেনশন-কম ফাইলগুলি সরাতে আমি এই আদেশটি ব্যবহার করছি:

mv -- !(*.jpg|*.png|*.bmp) targetdir/

উত্তর:


82

xargsকাজের জন্য সরঞ্জাম। যে, বা findসাথে -exec … {} +। এই সরঞ্জামগুলি বহুবার একটি কমান্ড চালায়, যতগুলি যুক্তি এক সাথে যেতে পারে।

পরিবর্তনশীল আর্গুমেন্টের তালিকাটি যখন শেষ হয় তখন উভয় পদ্ধতিই কার্যকর করা সহজ, যা এখানে ক্ষেত্রে হয় না: এর চূড়ান্ত যুক্তি mvহ'ল গন্তব্য। জিএনইউ ইউটিলিটিগুলির সাথে (অর্থাত্ এমবেডেড লিনাক্স বা সাইগউইন-তে) প্রথমে গন্তব্যটি পাস করার -tবিকল্পটি mvকার্যকর।

যদি ফাইলের নামগুলির কোনও শ্বেত স্থান বা কোনও কোনও না থাকে \"'তবে আপনি কেবলমাত্র ফাইলের নামগুলিতে ইনপুট হিসাবে সরবরাহ করতে পারেন xargs( echoকমান্ডটি ব্যাশ অন্তর্নির্মিত, সুতরাং এটি কমান্ড লাইনের দৈর্ঘ্যের সীমা সাপেক্ষে নয়):

echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir

আপনি ডিফল্ট উদ্ধৃত বিন্যাসের পরিবর্তে নাল-সীমাবদ্ধ ইনপুট ব্যবহার করতে -0বিকল্পটি ব্যবহার করতে পারেন xargs

printf '%s\0' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir

বিকল্পভাবে, আপনি ফাইলগুলির নামের তালিকা তৈরি করতে পারেন find। সাব-ডিরেক্টরিতে পুনরাবৃত্তি এড়াতে, ব্যবহার করুন -type d -prune। যেহেতু তালিকাবদ্ধ চিত্র ফাইলগুলির জন্য কোনও ক্রিয়া নির্দিষ্ট করা হয়নি, কেবলমাত্র অন্য ফাইলগুলি সরানো হয়েছে।

find . -name . -o -type d -prune -o \
       -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \
       -exec mv -t targetdir/ {} +

(এতে শেল ওয়াইল্ডকার্ড পদ্ধতির বিপরীতে ডট ফাইল রয়েছে)

আপনার যদি জিএনইউ ইউটিলিটি না থাকে তবে আপনি যুক্তিটি সঠিক ক্রমে পেতে একটি মধ্যবর্তী শেল ব্যবহার করতে পারেন। এই পদ্ধতিটি সমস্ত পসিক্স সিস্টেমে কাজ করে।

find . -name . -o -type d -prune -o \
       -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \
       -exec sh -c 'mv "$@" "$0"' targetdir/ {} +

Zsh, আপনি লোড করতে পারেন mvbuiltin :

setopt extended_glob
zmodload zsh/files
mv -- ^*.(jpg|png|bmp) targetdir/

বা যদি আপনি mvএবং অন্যান্য নামগুলি বাহ্যিক আদেশগুলি উল্লেখ করতে চান তবে:

setopt extended_glob
zmodload -Fm zsh/files b:zf_\*
zf_mv -- ^*.(jpg|png|bmp) targetdir/

বা ksh- শৈলী গ্লোব সহ:

setopt ksh_glob
zmodload -Fm zsh/files b:zf_\*
zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/

বিকল্পভাবে, জিএনইউ mvএবং zargs:

autoload -U zargs
setopt extended_glob
zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/

1
প্রথম দুটি কমান্ড "-বাশ:!: ইভেন্ট খুঁজে পাওয়া যায় নি" এবং দুটি পরবর্তী কোনও ফাইল সরানো হয়নি any আমি সেন্টোস 6.5 এ আছি যদি আপনার জানা উচিত
ডমিনিক

1
@ ডোমিনিক আমি একই প্রশ্নটি ব্যবহার করেছি যা আপনি আপনার প্রশ্নে ব্যবহার করেছেন। আপনার shopt -s extglobএটি সক্ষম করতে হবে। আমি findকমান্ডগুলির একটি পদক্ষেপ মিস করেছি, আমি সেগুলি স্থির করেছি।
গিলস

"ফাইন্ড: অবৈধ অভিব্যক্তি; ফাইন্ড কমান্ডটি দিয়ে আমি এটি পাচ্ছি; আপনি বাইনারি অপারেটর '-o' ব্যবহার করেছেন যা এর আগে কিছুই ছিল না।" আমি এখন অন্যদের চেষ্টা করব।
ডোমিনিক

@ ডোমিনিক যে পোস্টগুলি findপোস্ট করেছেন (এখন) সেগুলি কাজ করে। কপি-পেস্ট করার সময় আপনার অবশ্যই একটি অংশ রেখে দেওয়া উচিত।
গিলস

গিলস, সন্ধানের আদেশগুলির জন্য, কেন "না" অপারেটর ব্যবহার করবেন না !? বিজোড় অনুভূতি অনুসরণের চেয়ে এটি আরও স্পষ্ট এবং সহজে বোঝা যায় -o। উদাহরণস্বরূপ,! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
সিভিফ্যান 21

13

যদি লিনাক্স কার্নেলের সাথে কাজ করা যথেষ্ট হয় তবে আপনি কেবল তা করতে পারেন

ulimit -s 100000

এটি কাজ করবে কারণ লিনাক্স কার্নেলে প্রায় 10 বছর আগে একটি প্যাচ অন্তর্ভুক্ত করেছিল যা আর্গুমেন্টের সীমাটিকে স্ট্যাক আকারের উপর ভিত্তি করে পরিবর্তিত করেছিল: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ কমিট /? আইডি = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba

আপডেট: আপনি যদি সাহসী বোধ করেন তবে বলতে পারেন

ulimit -s unlimited

এবং যতক্ষণ না আপনার পর্যাপ্ত পরিমাণ র‍্যাম থাকে আপনি কোনও শেল প্রসারণে ভাল থাকবেন।


এটি একটি হ্যাক। কীভাবে আপনি কীভাবে স্ট্যাক সীমাটি সেট করবেন তা জানবেন? এটি একই সেশনে শুরু হওয়া অন্যান্য প্রক্রিয়াগুলিকেও প্রভাবিত করে।
কুসালানন্দ

1
হ্যাঁ, এটি হ্যাক। বেশিরভাগ সময় এই ধরণের হ্যাকগুলি এক-বন্ধ হয়ে যায় (তবে আপনি কত বার ম্যানুয়ালি বিপুল পরিমাণে ফাইল সরিয়ে ফেলতে পারেন?)। আপনি যদি নিশ্চিত হন যে প্রক্রিয়াটি আপনার সমস্ত র‌্যাম খায় না, আপনি সেট করতে পারেন ulimit -s unlimitedএবং এটি কার্যত সীমাহীন ফাইলগুলির জন্য কাজ করবে।
মিক্কো রেন্টালাইনেন

সঙ্গে ulimit -s unlimitedপ্রকৃত কমান্ড লাইন সীমা 2 ^ 31 বা 2 গিগাবাইট হয়। ( MAX_ARG_STRLENকার্নেলের উত্সে))
মিক্কো রেন্টালাইনেন

9

অপারেটিং সিস্টেমের আর্গুমেন্ট পাসিং সীমা শেল ইন্টারপ্রেটারের মধ্যে ঘটে এমন বিস্তারের ক্ষেত্রে প্রযোজ্য না। সুতরাং xargsবা ব্যবহারের সাথে সাথে find, পৃথক mvকমান্ডগুলিতে প্রসেসিং ব্রেকআপ করার জন্য আমরা কেবল শেল লুপ ব্যবহার করতে পারি :

for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done

এটি কেবল পসিক্স শেল কমান্ড ভাষার বৈশিষ্ট্য এবং ইউটিলিটিগুলি ব্যবহার করে। এই ওয়ান-লাইনারটি ইন্ডেন্টেশন সহ পরিষ্কার করা হয়েছে, অপ্রয়োজনীয় সেমিকোলনগুলি সরানো হয়েছে:

for x in *; do
  case "$x" in
    *.jpg|*.png|*.bmp) 
       ;; # nothing
    *) # catch-all case
       mv -- "$x" target
       ;;
  esac
done

এক মিলিয়নেরও বেশি ফাইল সহ, mvএটি findপোস্ট করা গিলস পোস্ট করা পসিক্স সমাধান ব্যবহারের জন্য প্রয়োজনীয় কয়েকটি পরিবর্তে এক মিলিয়নেরও বেশি প্রক্রিয়া তৈরি করবে । অন্য কথায়, এই উপায়ের ফলে প্রচুর অপ্রয়োজনীয় সিপিইউ মন্থন হয়।
সিভিফ্যান

@ সিআইভিফ্যান আরেকটি সমস্যা নিজেকে বিশ্বাস করছে যে পরিবর্তিত সংস্করণটি মূলটির সমতুল্য। এটি সহজেই দেখতে পাওয়া যায় যে বেশ কয়েকটি এক্সটেনশান ফিল্টার করার caseজন্য *সম্প্রসারণের ফলাফলের বিবৃতিটি মূল !(*.jpg|*.png|*.bmp)অভিব্যক্তির সমতুল্য । findউত্তর সত্য সমতুল্য না হয়; এটি উপ-ডিরেক্টরিতে নেমে আসে (আমি কোনও -maxdepthপ্রাকটিক দেখি না )।
কাজ

-name . -o -type d -prune -oউপ-ডিরেক্টরিতে নামা থেকে রক্ষা করে। -maxdepthদৃশ্যত পসিক্স অনুগত নয়, যদিও এটি আমার findম্যান পৃষ্ঠাতে উল্লেখ করা হয়নি ।
সিভিফ্যান

পুনর্বিবেচনায় ফিরে রোলড ১. উত্স বা গন্তব্য ভেরিয়েবল সম্পর্কে প্রশ্নটি কিছু বলে না, সুতরাং এটি উত্তরে অপ্রয়োজনীয় ক্রাফ্ট যুক্ত করে।
কাজ

5

এর আগে দেওয়া প্রস্তাবের চেয়ে আরও আক্রমণাত্মক সমাধানের জন্য, আপনার কার্নেল উত্সটি টানুন এবং সম্পাদনা করুন include/linux/binfmts.h

MAX_ARG_PAGES32-র চেয়ে বড় কোনও কিছুর আকার বাড়ান This এটি কার্নেলটি প্রোগ্রাম আর্গুমেন্টগুলির জন্য মেমরির পরিমাণ বাড়িয়ে দেয়, এর ফলে আপনাকে মিলিয়ন ফাইল বা আপনি যা কিছু করতে যাচ্ছেন তার জন্য আপনাকে নির্দেশ mvবা rmকমান্ড নির্দিষ্ট করতে দেয় । পুনরায় কম্পাইল করুন, ইনস্টল করুন, পুনরায় বুট করুন।

হুঁশিয়ার! যদি আপনি এটি আপনার সিস্টেমে মেমোরির জন্য খুব বড় সেট করে থাকেন এবং তারপরে প্রচুর আর্গুমেন্ট দিয়ে একটি কমান্ড চালান খারাপ কাজগুলি ঘটবে! মাল্টি-ইউজার সিস্টেমগুলিতে এটি করতে অত্যন্ত সতর্ক হন, দূষিত ব্যবহারকারীদের পক্ষে আপনার সমস্ত স্মৃতি ব্যবহার করা সহজ করে তোলে!

আপনি যদি নিজের কার্নেলটি পুনরায় সংকলন করতে এবং ম্যানুয়ালি পুনরায় ইনস্টল করতে না জানেন তবে সম্ভবত এই উত্তরটি বর্তমানে উপস্থিত নেই বলে আপনি সম্ভবত সবচেয়ে ভাল।


5

"$origin"/!(*.jpg|*.png|*.bmp)ক্যাচ ব্লকের পরিবর্তে আরও সাধারণ সমাধান :

for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done

ধন্যবাদ @ স্কোর_উন্ডার

একটি বহু-লাইন স্ক্রিপ্টের জন্য আপনি নিম্নলিখিতটি করতে পারেন ( বাদ পড়ার ;আগে লক্ষ্য করুন done):

for file in "$origin"/!(*.jpg|*.png|*.bmp); do        # don't copy types *.jpg|*.png|*.bmp
    mv -- "$file" "$destination" 
done 

আরও সাধারণকরণযুক্ত সমাধান করতে যা সমস্ত ফাইলকে সরিয়ে দেয়, আপনি ওয়ান-লাইনারটি করতে পারেন:

for file in "$origin"/*; do mv -- "$file" "$destination" ; done

যদি আপনি ইন্ডেন্টেশন করেন তবে এটির মতো দেখতে:

for file in "$origin"/*; do
    mv -- "$file" "$destination"
done 

এটি প্রতিটি ফাইলের উত্স নেয় এবং এগুলি একে একে গন্তব্যে নিয়ে যায়। $fileফাইলের নামগুলিতে শূন্যস্থান বা অন্যান্য বিশেষ অক্ষর থাকলে আশেপাশে উদ্ধৃতিগুলি প্রয়োজনীয়।

এই পদ্ধতির উদাহরণ যা নিখুঁতভাবে কাজ করেছে

for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
    mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
done

যা চাওয়া হচ্ছে তার কাছাকাছি সমাধান পেতে আপনি লুপটিতে মূল গ্লোব জাতীয় কিছু ব্যবহার করতে পারেন।
স্কোর_উন্ড

আসল গ্লোব বলতে কী বোঝ?
হোয়াইট্যাট

দুঃখিত যে একটু রহস্যপূর্ণ ছিলাম আমি প্রশ্নে উল্লিখিত glob উল্লেখ করা হয়েছে: !(*.jpg|*.png|*.bmp)। আপনি এটি গ্লোবাইং করে আপনার লুপটিতে যুক্ত করতে পারেন "$origin"/!(*.jpg|*.png|*.bmp)যা কাজীর উত্তরে ব্যবহৃত স্যুইচটির প্রয়োজনীয়তা এড়াতে এবং ফর্মের লুপের সরল দেহকে বজায় রাখতে পারে।
স্কোর_উন্ড

দুর্দান্ত স্কোর। আমি আপনার মন্তব্য অন্তর্ভুক্ত এবং আমার উত্তর আপডেট।
হোয়াইট্যাট

3

কখনও কখনও কেবল একটি ছোট স্ক্রিপ্ট লেখা সহজ, উদাহরণস্বরূপ পাইথনে:

import glob, shutil

for i in glob.glob('*.jpg'):
  shutil.move(i, 'new_dir/' + i)

1

আপনি যদি এই নিষেধাজ্ঞাকে প্রায় mvকয়েকবার চালাতে আপত্তি না করেন তবে এখনও ব্যবহার করার সময় আপনি এটি পেতে পারেন ।

আপনি একবারে অংশগুলি সরাতে পারেন। উদাহরণস্বরূপ বলি যে আপনার কাছে আলফানিউমেরিক ফাইলের নামের একটি দীর্ঘ তালিকা ছিল।

mv ./subdir/a* ./

ওই কাজগুলো. তারপরে আর একটি বড় অংশ ছিটকে দিন। কয়েকটা সরানোর পরে, আপনি কেবল ব্যবহারে ফিরে যেতে পারেনmv ./subdir/* ./


0

এখানে আমার দুটি সেন্ট, এটি এতে যুক্ত করুন .bash_profile

mv() {
  if [[ -d $1 ]]; then #directory mv
    /bin/mv $1 $2
  elif [[ -f $1 ]]; then #file mv
    /bin/mv $1 $2
  else
    for f in $1
    do
      source_path=$f
      #echo $source_path
      source_file=${source_path##*/}
      #echo $source_file
      destination_path=${2%/} #get rid of trailing forward slash

      echo "Moving $f to $destination_path/$source_file"

      /bin/mv $f $destination_path/$source_file
    done
  fi
}
export -f mv

ব্যবহার

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