linux - ماهو - unix شرح




قائمة وسيطة طويلة جدا للأوامر rm ، cp ، mv (18)

ليرة تركية، والدكتور

إنها قيود kernel على حجم وسيطة سطر الأوامر. استخدم حلقة for بدلاً من ذلك.

أصل المشكلة

هذه مشكلة في نظام ، تتعلق execve و ARG_MAX ثابت. هناك الكثير من الوثائق حول هذا الموضوع (انظر: execve man ، exict debian's wiki ).

بشكل أساسي ، ينتج التوسيع أمرًا ( ARG_MAX ) يتجاوز حد ARG_MAX . على kernel 2.6.23 ، تم تعيين الحد في 128 kB . تم زيادة هذا الثابت ويمكنك الحصول على قيمته عن طريق التنفيذ:

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic

حل

استخدم حلقة for it as BashFAQ/095 على BashFAQ/095 ولا يوجد حد باستثناء ذاكرة RAM / الذاكرة:

for f in *.pdf; do rm "$f"; done

أيضا هذا هو نهج المحمولة كما غلوب لديها سلوك قوي ومتسق بين قذائف ( جزء من المواصفات POSIX ).

إذا كنت تصر ، يمكنك استخدام find ولكن في الحقيقة لا تستخدم xargs لأنها "خطيرة (مكسورة ، قابلة للاستغلال ، إلخ) عند قراءة مدخلات غير NUL- محددة" :

find . -name '*.pdf' -exec rm {} +

المراجع

لدي عدة مئات من ملفات PDF تحت دليل في UNIX. أسماء ملفات PDF طويلة للغاية (حوالي 60 حرفًا).

عندما أحاول حذف جميع ملفات PDF معًا باستخدام الأمر التالي:

rm -f *.pdf

أحصل على الخطأ التالية:

/bin/rm: cannot execute [Argument list too long]

ما هو الحل لهذا الخطأ؟ هل يحدث هذا الخطأ لأوامر mv و cp أيضًا؟ إذا كانت الإجابة بنعم ، كيف يمكن حل هذه الأوامر؟


أنا فقط أعرف طريقة حول هذا. الفكرة هي تصدير تلك القائمة من ملفات pdf لديك في ملف. ثم انقسم هذا الملف إلى عدة أجزاء. ثم قم بإزالة ملفات pdf المدرجة في كل جزء.

ls | grep .pdf > list.txt
wc -l list.txt

wc -l هو حساب عدد الخطوط التي تحتويها القائمة list.txt. عندما يكون لديك فكرة عن المدة التي تستغرقها ، يمكنك أن تقرر تقسيمها إلى النصف أو الرابع أو ما شابه. استخدام الأمر split -l على سبيل المثال ، تقسيمها في كل سطر 600 سطر.

split -l 600 list.txt

سيؤدي ذلك إلى إنشاء عدد قليل من الملفات المسمى xaa و xab و xac وما إلى ذلك يعتمد على كيفية تقسيمه. الآن "لاستيراد" كل قائمة في تلك الملفات إلى أمر rm ، استخدم هذا:

rm $(<xaa)
rm $(<xab)
rm $(<xac)

اسف على سوء لغتي الانجليزية.


إجابة أخرى هي فرض xargs لمعالجة الأوامر على دفعات. على سبيل المثال delete الملفات 100 في وقت واحد ، أدخل cd في الدليل وقم بتشغيل هذا:

echo *.pdf | xargs -n 100 rm


إذا كان لديك مشاكل مماثلة مع grep ، فإن الحل الأسهل هو الرجوع إلى ظهر واحد وإجراء بحث تكراري.

لذا بدلا من

grep "something" *

يمكنك استخدام:

cd ..
grep "something" -R search_in_this_dir/

لاحظ أنه سيتم بشكل متكرر البحث المجلدات الفرعية لدليل "search_in_this_dir" أيضاً.


إذا كنت تحاول حذف عدد كبير جدًا من الملفات في وقت واحد (حذفت مجلدًا يحتوي على أكثر من 485000 مستخدم حاليًا) ، فمن المحتمل أن تصل إلى هذا الخطأ:

/bin/rm: Argument list too long.

المشكلة هي أنه عند كتابة شيء مثل rm -rf * ، يتم استبدال * بقائمة بكل ملف مطابق ، مثل "rm -rf file1 file2 file3 file4" وهكذا. يوجد مخزن مؤقت صغير نسبياً من الذاكرة مخصص لتخزين قائمة الوسائط هذه وإذا تم ملؤها ، لن تقوم shell بتنفيذ البرنامج.

للتغلب على هذه المشكلة ، سيستخدم الكثير من الأشخاص أمر البحث للعثور على كل ملف وتمريره واحدًا تلو الآخر إلى أمر "rm" كما يلي:

find . -type f -exec rm -v {} \;

مشكلتي هي أنني احتجت إلى حذف 500،000 ملف ، وقد استغرق الأمر طويلا.

تعثرت على طريقة أسرع لحذف الملفات - الأمر "العثور على" يحتوي على "-delete" العلم بنيت في الحق! إليك ما انتهى به الأمر باستخدام:

find . -type f -delete

باستخدام هذه الطريقة ، قمت بحذف ملفات بمعدل 2000 ملف / ثانية - أسرع بكثير!

يمكنك أيضًا إظهار أسماء الملفات أثناء حذفها:

find . -type f -print -delete

... أو حتى إظهار عدد الملفات التي سيتم حذفها ، ثم تحديد الوقت الذي تستغرقه لحذفها:

[email protected]# ls -1 | wc -l && time find . -type f -delete
100000
real    0m3.660s
user    0m0.036s
sys     0m0.552s

إصدار أكثر أمانًا من استخدام xargs ، وليس أيضًا متكرر: ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done

تصفية أدلةنا هنا غير ضرورية إلى حد ما لأن 'rm' لن تحذفها على أي حال ، ويمكن إزالتها ببساطة ، ولكن لماذا يتم تشغيل شيء سيعيد بالتأكيد الخطأ؟


افترض إدخال اسم الدليل هو إدخال وإخراج دليل الإخراج الإخراج. ثم يمكنك استخدام حلقة بسيطة لنسخ كل شيء

for f in input/*
do
cp $f output
done

السبب في حدوث ذلك هو أن bash يقوم بالفعل بتوسيع العلامة النجمية إلى كل ملف مطابق ، مما يؤدي إلى إنشاء سطر أوامر طويل جدًا.

جرب هذا:

find . -name "*.pdf" -print0 | xargs -0 rm

تحذير: هذا هو بحث عودي وسوف تجد (وحذف) الملفات في الدلائل الفرعية كذلك. إذا كنت متأكدًا من أنك لا تريد تأكيدًا ، فيمكنك إجراء ذلك على -f لأمر rm فقط.

إذا كنت تستخدم Linux ، فيمكنك القيام بما يلي لجعل الأمر غير متكرر:

find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm

هناك خيار آخر يتمثل في استخدام علامة -delete :

find . -name "*.pdf" -delete

كنت تواجه نفس المشكلة أثناء نسخ دليل مصدر النموذج إلى الوجهة

كان الدليل المصدر ملفات ~ 3 lakcs

اعتدت النائب مع الخيار -r وأنها عملت بالنسبة لي

cp -r abc / def /

فإنه سيتم نسخ كافة الملفات من abc إلى def دون إعطاء تحذير من قائمة وسيطة طويلة جداً


لإزالة أول 100 ملف:

rm -rf 'ls | الرأس -100 "


لقد واجهت هذه المشكلة عدة مرات. سيقوم العديد من الحلول بتشغيل الأمر rm لكل ملف فردي يحتاج إلى حذفه. هذا غير فعال للغاية:

find . -name "*.pdf" -print0 | xargs -0 rm -rf

انتهى بي الأمر كتابة برنامج نصي python لحذف الملفات استنادًا إلى الأحرف الأربعة الأولى في اسم الملف:

import os
filedir = '/tmp/' #The directory you wish to run rm on 
filelist = (os.listdir(filedir)) #gets listing of all files in the specified dir
newlist = [] #Makes a blank list named newlist
for i in filelist: 
    if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlist
        newlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlist
for i in newlist:
    if 'tmp' in i:  #If statment to look for tmp in the filename/dirname
        print ('Running command rm -rf '+str(filedir)+str(i)+'* : File Count: '+str(len(os.listdir(filedir)))) #Prints the command to be run and a total file count
        os.system('rm -rf '+str(filedir)+str(i)+'*') #Actual shell command
print ('DONE')

هذا عمل جيد جدا بالنسبة لي. تمكنت من مسح أكثر من 2 مليون ملف مؤقت في مجلد في حوالي 15 دقيقة. لقد علقت على tar من القليل من التعليمات البرمجية بحيث يمكن لأي شخص لديه أدنى المعرفة لا python التلاعب بهذا الرمز.


لقد وجدت أنه بالنسبة لقوائم ملفات كبيرة للغاية (> 1e6) ، كانت هذه الإجابات بطيئة للغاية. هنا هو الحل باستخدام المعالجة المتوازية في بيثون. أعلم ، أعلم ، هذا ليس لينكس ... لكن لا شيء آخر يعمل هنا.

(هذا انقذني ساعات)

# delete files
import os as os
import glob
import multiprocessing as mp

directory = r'your/directory'
os.chdir(directory)


files_names = [i for i in glob.glob('*.{}'.format('pdf'))]

# report errors from pool

def callback_error(result):
    print('error', result)

# delete file using system command
def delete_files(file_name):
     os.system('rm -rf ' + file_name)

pool = mp.Pool(12)  
# or use pool = mp.Pool(mp.cpu_count())


if __name__ == '__main__':
    for file_name in files_names:
        print(file_name)
        pool.apply_async(delete_files,[file_name], error_callback=callback_error)

وواحدة أخرى:

cd  /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm

يبدو الخيار أدناه بسيطًا لهذه المشكلة. حصلت على هذه المعلومات من موضوع آخر لكنه ساعدني.

for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
    cp "$file" /opt/sw/op-storage/
done

فقط قم بتشغيل الأمر أعلاه وسيقوم بالمهمة.


يمكنك إنشاء مجلد مؤقت ، ونقل جميع الملفات والمجلدات الفرعية التي تريد الاحتفاظ بها في مجلد temp ثم حذف المجلد القديم وإعادة تسمية مجلد temp إلى المجلد القديم حاول هذا المثال حتى تكون على ثقة من القيام بذلك على الهواء مباشرة:

mkdir testit
cd testit
mkdir big_folder tmp_folder
touch big_folder/file1.pdf
touch big_folder/file2.pdf
mv big_folder/file1,pdf tmp_folder/
rm -r big_folder
mv tmp_folder big_folder

فإن rm -r big_folder سيزيل كل الملفات في big_folder بغض النظر عن عددهم. عليك فقط أن تكون حذرا للغاية أن يكون لديك أولا كل الملفات / المجلدات التي تريد الاحتفاظ بها ، في هذه الحالة كان file1.pdf


يمكنك استخدام صفيف باش:

files=(*.pdf)
for((I=0;I<${#files[*]};I+=1000)); do rm -f ${files[@]:I:1000}; done

بهذه الطريقة سيتم مسحها على دفعات من 1000 ملف لكل خطوة.


يمكنك تجربة هذا:

for f in *.pdf
do
  rm $f
done

EDIT: تعليق ThiefMaster يقترح علي عدم الكشف عن مثل هذه الممارسة الخطرة على jedis الشباب قذيفة ، لذلك سأضيف إصدار أكثر "أكثر أمنا" (من أجل الحفاظ على الأشياء عندما يكون شخص ما لديه ملف "-rf. ..pdf")

echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
   echo "rm -i $f" >> /tmp/dummy.sh
done

بعد تشغيل ما سبق ، فقط افتح الملف /tmp/dummy.sh في fav الخاص بك. محرر والتحقق من كل سطر واحد لأسماء ملفات خطرة ، والتعليق عليها إذا وجدت.

ثم نسخ البرنامج النصي dummy.sh في دير عملك وتشغيله.

كل هذا لأسباب أمنية.


find على إجراء -delete :

find . -maxdepth 1 -name '*.pdf' -delete




unix