سؤال

هناك طريقة بسيطة في معيار جميلة بيئة يونيكس مع باش لتشغيل الأمر إلى حذف كل شيء ولكن أحدث X الملفات من الدليل ؟

لإعطاء أكثر قليلا من مثال ملموس ، تخيل بعض وظيفة كرون كتابة ملف (مثلا ملف السجل أو القطران-ed للنسخ الاحتياطي) إلى دليل كل ساعة.أريد طريقة للحصول على آخر وظيفة كرون التوالي والذي من شأنه أن يزيل أقدم الملفات في هذا الدليل حتى يكون هناك أقل من 5.

و مجرد أن تكون واضحة, هناك ملف واحد فقط الوقت الحاضر ، لا ينبغي أبدا أن تحذف.

هل كانت مفيدة؟

المحلول

المشاكل مع القائمة الإجابات:

  • عدم القدرة على التعامل مع أسماء الملفات مع جزءا لا يتجزأ من مسافات أو أسطر.
    • في حالة حلول الاحتجاج rm مباشرة على المسعرة استبدال الأوامر (rm `...`) ، هناك خطر من غير مقصودة globbing.
  • عدم القدرة على التمييز بين الملفات والدلائل (أي إذا الدلائل حدث يكون بين 5 مؤخرا تعديل الملفات البنود, كنت الاحتفاظ بشكل فعال أقل من 5 ملفات وتطبيق rm إلى الدلائل سوف تفشل).

wnoise الجواب تتناول هذه القضايا ، ولكن الحل هو جنومحددة (و معقدة جدا).

هنا هو عملي ، متوافقة مع POSIX الحل التي تأتي فقط مع التحذير واحد:فإنه لا يمكن التعامل مع أسماء الملفات مع جزءا لا يتجزأ من أسطر - ولكن أنا لا أعتبر أن العالم الحقيقي القلق بالنسبة لمعظم الناس.

للعلم هنا تفسير لما عموما أنها ليست فكرة جيدة أن تحليل ls الإخراج: http://mywiki.wooledge.org/ParsingLs

ls -tp | grep -v '/$' | tail -n +6 | xargs -I {} rm -- {}

أعلاه هو غير فعالة, لأن xargs وقد الاحتجاج rm مرة واحدة كل اسم الملف.
النظام الأساسي الخاص بك هو xargs قد تسمح لك لحل هذه المشكلة:

إذا كان لديك جنو xargs, استخدام -d '\n', مما يجعل xargs النظر في كل سطر الإدخال منفصل الحجة ، ولكن يمر العديد من الحجج كما سيكون مناسبا على سطر الأوامر في مرة واحدة:

ls -tp | grep -v '/$' | tail -n +6 | xargs -d '\n' -r rm --

-r (--no-run-if-empty) يضمن rm عدم الاحتجاج إذا كان هناك أي إدخال.

إذا كان لديك BSD xargs (بما في ذلك على OS X) يمكنك استخدام -0 التعامل مع NUL-فصل الإدخال بعد أول ترجمة أسطر إلى NUL (0x0) حرف., الذي يمر أيضا (عادة) كل أسماء في مرة واحدة (سوف نعمل أيضا مع جنو xargs):

ls -tp | grep -v '/$' | tail -n +6 | tr '\n' '\0' | xargs -0 rm --

التفسير:

  • ls -tp يطبع أسماء الملفات البنود مرتبة حسب مدى مؤخرا تم تعديل في ترتيب تنازلي (البنود المعدلة مؤخرا أول) (-t) مع الدلائل المطبوعة مع زائدة / إلى وضع علامة عليها على هذا النحو (-p).
  • grep -v '/$' ثم يتخلص من الدلائل من الناتج القائمة من خلال حذف (-v) الخطوط التي زائدة / (/$).
    • التحذير:منذ الارتباط الرمزي الذي يشير إلى دليل هو من الناحية الفنية لا حد ذاته دليل ، مثل روابط الرمزية سوف لا يمكن استبعادها.
  • tail -n +6 يتخطى الأولى 5 الإدخالات في القائمة ، في تأثير عودة جميع ولكن 5 مؤخرا تعديل الملفات ، إن وجدت.
    لاحظ أنه من أجل استبعاد N الملفات ، N+1 يجب أن يتم تمرير إلى tail -n +.
  • xargs -I {} rm -- {} (وتنوعاتها) ثم تحتج على rm على كل هذه الملفات ؛ إذا كان هناك أي مباريات في كل شيء ، xargs لن تفعل أي شيء.
    • xargs -I {} rm -- {} ويعرف النائب {} يمثل كل سطر الإدخال ككل, لذا rm ثم الاحتجاج مرة واحدة لكل سطر الإدخال ، ولكن مع أسماء الملفات مع جزءا لا يتجزأ من المساحات التعامل معها بشكل صحيح.
    • -- في جميع الحالات يضمن أن أي أسماء الملفات التي يحدث أن تبدأ مع - لا مخطئا خيارات قبل rm.

A الاختلاف على المشكلة الأصلية ، في حالة مطابقة الملفات التي تحتاج إلى معالجتها بشكل فردي أو جمعت في شل مجموعة:

# One by one, in a shell loop (POSIX-compliant):
ls -tp | grep -v '/$' | tail -n +6 | while IFS= read -r f; do echo "$f"; done

# One by one, but using a Bash process substitution (<(...), 
# so that the variables inside the `while` loop remain in scope:
while IFS= read -r f; do echo "$f"; done < <(ls -tp | grep -v '/$' | tail -n +6)

# Collecting the matches in a Bash *array*:
IFS=$'\n' read -d '' -ra files  < <(ls -tp | grep -v '/$' | tail -n +6)
printf '%s\n' "${files[@]}" # print array elements

نصائح أخرى

إزالة جميع ولكن 5 (أو أي عدد) من أحدث الملفات في الدليل.

rm `ls -t | awk 'NR>5'`
(ls -t|head -n 5;ls)|sort|uniq -u|xargs rm

هذا الإصدار يدعم أسماء الأماكن:

(ls -t|head -n 5;ls)|sort|uniq -u|sed -e 's,.*,"&",g'|xargs rm

أبسط البديل thelsdj الجواب:

ls -tr | head -n -5 | xargs --no-run-if-empty rm 

ls-tr يعرض جميع الملفات الأقدم أولا (-t أحدث أولا ، - r العكسي).

رئيس -ن -5 يعرض كل 5 السطور الأخيرة (أي 5 الملفات الأحدث).

xargs rm المكالمات rm لكل الملف المحدد.

find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -r -z -n | awk 'BEGIN { RS="\0"; ORS="\0"; FS="" } NR > 5 { sub("^[0-9]*(.[0-9]*)? ", ""); print }' | xargs -0 rm -f

يتطلب جنو تجد -printf و غنو النوع -z و غنو awk ل "\0", و غنو xargs عن -0 ، ولكن مقابض الملفات مع جزءا لا يتجزأ من أسطر أو مسافات.

كل هذه الإجابات تفشل عندما يكون هناك أدلة في الدليل الحالي.هنا شيء أن يعمل:

find . -maxdepth 1 -type f | xargs -x ls -t | awk 'NR>5' | xargs -L1 rm

هذا:

  1. يعمل عندما يكون هناك أدلة في الدليل الحالي

  2. يحاول إزالة كل الملفات حتى لو كانت في السابق لا يمكن إزالتها (بسبب أذونات.... الخ)

  3. فشل آمنة عند عدد من الملفات في الدليل الحالي هو المفرط ، xargs عادة ما تبا لك أكثر ( -x)

  4. لا تلبي مسافات في أسماء (ربما كنت تستخدم الخطأ OS؟)

ls -tQ | tail -n+4 | xargs rm

قائمة أسماء الملفات قبل التعديل الوقت ، عن كل اسم.استبعاد أول 3 (3 الأخيرة).إزالة المتبقية.

تحرير بعد مفيدة تعليق من mklement0 (شكرا):تصحيح -n+3 الجدال ملاحظة هذا لن يعمل كما هو متوقع إذا أسماء الملفات تحتوي على أسطر و/أو دليل يحتوي على الدلائل.

تجاهل الأسطر الجديدة هو تجاهل الأمن وحسن الترميز.wnoise كان فقط إجابة جيدة.هنا هو الاختلاف على أن يضع أسماء الملفات في مجموعة $x

while IFS= read -rd ''; do 
    x+=("${REPLY#* }"); 
done < <(find . -maxdepth 1 -printf '%T@ %p\0' | sort -r -z -n )

إذا أسماء الملفات لا تحتوي على مسافات هذا العمل:

ls -C1 -t| awk 'NR>5'|xargs rm

إذا أسماء الملفات لا تحتوي على مسافات ، شيء من هذا القبيل

ls -C1 -t | awk 'NR>5' | sed -e "s/^/rm '/" -e "s/$/'/" | sh

المنطق الأساسي:

  • الحصول على قائمة من الملفات في النظام, عمود واحد
  • الحصول على جميع ولكن أول 5 (n=5 على سبيل المثال)
  • النسخة الأولى:إرسال هؤلاء إلى rm
  • النسخة الثانية:gen السيناريو الذي سيتم إزالتها بشكل صحيح

مع zsh

على افتراض انك لا تهتم تقديم الدلائل و سوف لا يكون لديك أكثر من 999 الملفات (اختيار عدد أكبر إذا كنت تريد ، أو إنشاء حلقة while).

[ 6 -le `ls *(.)|wc -l` ] && rm *(.om[6,999])

في *(.om[6,999]), ، . يعني الملفات ، o يعني ترتيب الفرز ، m يعني حسب تاريخ التعديل (وضع a من أجل الوصول إلى الوقت أو c بالنسبة inode تغيير) ، [6,999] يختار مجموعة من الملف حتى لا rm 5 الأولى.

أدرك أن هذا الموضوع القديم, ولكن ربما شخص ما سوف تستفيد من هذا.هذا الأمر سوف تجد الملفات في الدليل الحالي :

for F in $(find . -maxdepth 1 -type f -name "*_srv_logs_*.tar.gz" -printf '%T@ %p\n' | sort -r -z -n | tail -n+5 | awk '{ print $2; }'); do rm $F; done

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

find . -maxdepth 1 -type f -name "*_srv_logs_*.tar.gz" -printf '%T@ %p\n'

المقبل ، فرزها حسب الطوابع الزمنية:

sort -r -z -n

ثم تدق قبالة 4 أحدث الملفات من القائمة:

tail -n+5

الاستيلاء على العمود 2 (اسم ليس الزمني):

awk '{ print $2; }'

ثم لف أن كل شيء في هذا البيان:

for F in $(); do rm $F; done

قد يكون هذا أكثر مطول الأمر ، ولكن كان أفضل بكثير الحظ أن تكون قادرة على استهداف المشروط الملفات وتنفيذ المزيد من الأوامر المعقدة ضدهم.

وجدت للاهتمام cmd في Sed-Onliners - حذف آخر 3 خطوط - fnd يجعلها مثالية طريقة أخرى الجلد القط (لا) ولكن الفكرة:

 #!/bin/bash
 # sed cmd chng #2 to value file wish to retain

 cd /opt/depot 

 ls -1 MyMintFiles*.zip > BigList
 sed -n -e :a -e '1,2!{P;N;D;};N;ba' BigList > DeList

 for i in `cat DeList` 
 do 
 echo "Deleted $i" 
 rm -f $i  
 #echo "File(s) gonzo " 
 #read junk 
 done 
 exit 0

يزيل جميع ولكن أحدث 10 (معظم حديثي) الملفات

ls -t1 | head -n $(echo $(ls -1 | wc -l) - 10 | bc) | xargs rm

إذا كانت أقل من 10 ملفات لا يتم إزالة الملف و سوف يكون لديك :خطأ الرأس:غير خط العد -- 0

عد الملفات مع باش

أنا في حاجة حلا busybox (راوتر) ، xargs أو مجموعة الحلول غير مجدية بالنسبة لي - لا يوجد مثل هذا الأمر المتاحة هناك.ابحث mtime ليست الإجابة الصحيحة كما أننا نتحدث عن 10 عناصر و ليس بالضرورة 10 أيام.اسبو الجواب كان أقصر و أنظف و على الأرجح الأكثر unversal واحد.

خطأ مع المساحات و عندما لا الملفات المراد حذفها على حد سواء ببساطة حلها الطريقة القياسية:

rm "$(ls -td *.tar | awk 'NR>7')" 2>&-

اكثر التعليمية الإصدار:يمكننا أن نفعل كل شيء إذا أردنا استخدام awk بشكل مختلف.عادة انا استخدم هذه الطريقة لتمرير (عودة) المتغيرات من awk إلى sh.كما نقرأ في كل وقت أنه لا يمكن القيام به ، أختلف:هنا هو طريقة.

مثلا .القطران الملفات مع أي مشكلة بخصوص المسافات في اسم الملف.لاختبار, محل "rm" مع "هل".

eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')

التفسير:

ls -td *.tar يسرد كافة .القطران الملفات مرتبة حسب الوقت.تنطبق على جميع الملفات في المجلد الحالي, إزالة "د *.القطران" جزء

awk 'NR>7... يتخطى أول 7 خطوط

print "rm \"" $0 "\"" يبني خط:rm "اسم الملف"

eval تنفيذ ذلك

منذ أن تستخدم rm, لن تستخدم الأوامر أعلاه في السيناريو!حكمة الاستخدام هي:

(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))

في حالة استخدام ls -t الأمر لن تفعل أي ضرر على سخيفة مثل هذه الأمثلة: touch 'foo " bar' و touch 'hello * world'.ليس لدينا أي وقت مضى خلق الملفات مع أسماء مثل في الحياة الحقيقية!

Sidenote.إذا أردنا تمرير متغير إلى sh بهذه الطريقة ، فإننا ببساطة تعديل طباعة (شكل بسيط, لا مسافات السكوت):

print "VarName="$1

تعيين المتغير VarName قيمة $1.متغيرات متعددة يمكن أن تنشأ دفعة واحدة.هذا VarName يصبح من الطبيعي sh متغير يمكن أن تستخدم عادة في السيناريو أو قذيفة بعد ذلك.ذلك أن إنشاء المتغيرات مع awk و تعيد لهم قذيفة:

eval $(ls -td *.tar | awk 'NR>7 { print "VarName=\""$1"\""  }'); echo "$VarName"
leaveCount=5
fileCount=$(ls -1 *.log | wc -l)
tailCount=$((fileCount - leaveCount))

# avoid negative tail argument
[[ $tailCount < 0 ]] && tailCount=0

ls -t *.log | tail -$tailCount | xargs rm -f

أنا جعلت هذا في باش قذيفة النصي.الاستخدام: keep NUM DIR حيث NUM هو عدد الملفات للحفاظ ودير هو الدليل فرك.

#!/bin/bash
# Keep last N files by date.
# Usage: keep NUMBER DIRECTORY
echo ""
if [ $# -lt 2 ]; then
    echo "Usage: $0 NUMFILES DIR"
    echo "Keep last N newest files."
    exit 1
fi
if [ ! -e $2 ]; then
    echo "ERROR: directory '$1' does not exist"
    exit 1
fi
if [ ! -d $2 ]; then
    echo "ERROR: '$1' is not a directory"
    exit 1
fi
pushd $2 > /dev/null
ls -tp | grep -v '/' | tail -n +"$1" | xargs -I {} rm -- {}
popd > /dev/null
echo "Done. Kept $1 most recent files in $2."
ls $2|wc -l

يعمل على ديبيان (تحمل نفس على أخرى توزيعات أحصل على:rm:لا يمكن إزالة الدليل `..'

وهو أمر مزعج جدا..

على أي حال أنا أنب أعلاه وأضاف أيضا البقرى إلى الأمر.في حالتي لدي 6 ملفات النسخ الاحتياطي في دليل مثلاfile1.القطران file2.القطران file3.القطران وغيرها ، أريد فقط حذف ملف أقدم (إزالة الملف الأول في حالتي)

السيناريو ركضت إلى حذف أقدم الملف:

ls-C1 -t| grep الملف | awk 'NR>5'|xargs rm

هذا (على النحو الوارد أعلاه) حذف أول من الملفات مثلfile1.القطران هذا أيضا يترك يكون مع file2 file3 file4 file5 و file6

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top