حذف كل شيء ولكن أحدث X الملفات في باش
سؤال
هناك طريقة بسيطة في معيار جميلة بيئة يونيكس مع باش لتشغيل الأمر إلى حذف كل شيء ولكن أحدث 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
هذا:
يعمل عندما يكون هناك أدلة في الدليل الحالي
يحاول إزالة كل الملفات حتى لو كانت في السابق لا يمكن إزالتها (بسبب أذونات.... الخ)
فشل آمنة عند عدد من الملفات في الدليل الحالي هو المفرط ،
xargs
عادة ما تبا لك أكثر (-x
)لا تلبي مسافات في أسماء (ربما كنت تستخدم الخطأ 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