วิธีที่รวดเร็วและไม่ซับซ้อนเกินไปในการลบไฟล์ทั้งหมดในไดเรกทอรีที่มีความยาว x บรรทัดในทุบตีคืออะไร
วิธีที่รวดเร็วและไม่ซับซ้อนเกินไปในการลบไฟล์ทั้งหมดในไดเรกทอรีที่มีความยาว x บรรทัดในทุบตีคืออะไร
คำตอบ:
นี่เป็นวิธีแก้ปัญหา POSIX ที่ควรเข้าใจง่าย:
find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;
เช่นเดียวกับคำตอบของสเตฟานให้ลบechoความสุขเมื่อมีสิ่งที่จะถูกลบออก
จุด.แสดงถึงไดเรกทอรีปัจจุบัน findค้นหาไฟล์และไดเรกทอรีซ้ำภายใน.และสามารถทำสิ่งต่าง ๆ กับพวกเขา
-typeเป็นหนึ่งในfind's พรรค ; เป็นการทดสอบที่จะดำเนินการสำหรับแต่ละไฟล์และไดเรกทอรีที่พบซ้ำ (ภายใน.) และส่วนที่เหลือของกลุ่มในบรรทัดจะได้รับการประเมินหากผลลัพธ์นี้เป็น "true" เท่านั้น
ในกรณีนี้เราจะดำเนินการต่อถ้าเราจัดการกับไฟล์ปกติไม่ใช่ไดเรกทอรีหรือสิ่งอื่นใด (เช่นอุปกรณ์บล็อก)
การเรียก-execหลัก (ของfind) เรียกคำสั่งภายนอกและดำเนินต่อไปยังหลักถัดไปเท่านั้นหากคำสั่งภายนอกออกจากการสำเร็จ (สถานะออกเป็น "0") {}จะถูกแทนที่ด้วยชื่อไฟล์ที่ถูก "พิจารณา" โดยfindคำสั่ง ดังนั้นการ-execเรียกครั้งแรกจะเทียบเท่ากับคำสั่งเชลล์ต่อไปนี้ซึ่งดำเนินการสำหรับแต่ละไฟล์ตามลำดับ:
awk -v x=10 'NR==x{exit 1}' ./somefilename
Awk เป็นภาษาทั้งหมดในตัวเองออกแบบมาสำหรับการจัดการไฟล์ข้อความที่คั่นด้วยเช่น CSV เงื่อนไข Awk และคำสั่ง (ซึ่งมีอยู่ระหว่างเครื่องหมายคำพูดเดี่ยวและเริ่มต้นด้วยตัวอักษรNR) จะถูกดำเนินการสำหรับทุกบรรทัดของไฟล์ข้อความ (การวนซ้ำโดยนัย)
หากต้องการเรียนรู้ Awk อย่างสมบูรณ์ฉันขอแนะนำGrymoire Tutorialแต่ฉันจะอธิบายคุณลักษณะ Awk ที่ใช้ในคำสั่งด้านบน
-vธง Awk ช่วยให้เราสามารถตั้งค่าตัวแปร Awk (ครั้งเดียว) ก่อนที่จะมีคำสั่ง Awk จะดำเนินการ (สำหรับแต่ละบรรทัดของไฟล์.) ในกรณีนี้เราตั้งไปx10
NRเป็นตัวแปร Awk พิเศษที่อ้างถึง " N umber ของR ecord ปัจจุบัน" มันคือหมายเลขบรรทัดที่เรากำลังดูในการส่งผ่านลูปใด ๆ
(หมายเหตุว่ามันเป็นไปได้ แต่ที่ผิดปกติในการใช้ที่แตกต่างกัน " R ecord S eparator" กว่าค่าเริ่มต้นของตัวอักษรขึ้นบรรทัดใหม่โดยการตั้งค่าRS. นี่คือตัวอย่างของการเล่นที่มีการบันทึกแยก. )
สคริปต์ Awk โดยทั่วไปประกอบด้วยเงื่อนไข (นอกวงเล็บปีกกา) รวมกับการกระทำ (ภายในวงเล็บปีกกา) สามารถมีเงื่อนไขผสมและการกระทำผสมและมีเงื่อนไขเริ่มต้น (จริง) และการกระทำเริ่มต้น (พิมพ์) แต่เราต้องการ ไม่ต้องกังวลกับสิ่งเหล่านั้น
สภาพที่นี่คือ "นี่คือบรรทัดที่ 10 ได้หรือไม่" หากเป็นกรณีนี้เราจะออกด้วยสถานะการออกที่ไม่เป็นศูนย์ซึ่งในการเขียนสคริปต์เชลล์หมายถึง "การยกเลิกคำสั่งที่ไม่สำเร็จ"
ดังนั้นวิธีเดียวที่คำสั่งนี้ Awk จะออกจากที่ประสบความสำเร็จคือถ้าจุดสิ้นสุดของแฟ้มจะถึงก่อนบรรทัดที่ 10 จะมาถึง
ดังนั้นหากสคริปต์ Awk ออกสำเร็จหมายความว่าคุณมีไฟล์น้อยกว่าสิบบรรทัด
การ-execเรียกครั้งต่อไป(ถ้าคุณลบออกecho) จะลบแต่ละไฟล์ (ซึ่งจะทำให้มีการประเมินค่าของไฟล์find) ในการรัน:
rm -f ./somefilename
สมมติว่าการfindติดตั้งที่รองรับเพรดิเคต-readable(หากคุณfindไม่รองรับให้ลบออกคุณจะได้รับข้อความแสดงข้อผิดพลาดสำหรับไฟล์ที่อ่านไม่ได้หรือแทนที่ด้วย-exec test -r {} \;):
x=10 find . -type f -readable -exec sh -c '
for file do
lines=$(wc -l < "$file") && [ "$((lines))" -lt "$x" ] && echo rm -f "$file"
done' sh {} +
ลบechoหากมีความสุข
นั่นคือไม่ได้มีประสิทธิภาพโดยเฉพาะอย่างยิ่งในการที่จะนับทุกสายในทุกไฟล์ในขณะที่มันเพียงต้องการที่จะหยุดที่xวันหนึ่งและมันจะทำงานอย่างใดอย่างหนึ่งwc(และอาจหนึ่งrm) คำสั่งสำหรับแต่ละไฟล์
ด้วย GNU awkคุณสามารถทำให้มีประสิทธิภาพมากขึ้นด้วย:
x=10
find . -type f -readable -exec awk -v x="$x" -v ORS='\0' '
FNR == x {nextfile}
ENDFILE {if (FNR < x) print FILENAME}' {} +|
xargs -r0 echo rm -f
(ลบอีกครั้งechoเมื่อมีความสุข)
เช่นเดียวกันกับperl:
x=10 find . -type f -readable -exec perl -Tlne '
if ($. == $ENV{x}) {close ARGV}
elsif (eof) {print $ARGV; close ARGV}' {} +
แทนที่printด้วยunlinkหากมีความสุข
shคือสิ่งที่เกิดขึ้นในสคริปต์แบบอินไลน์ของ$0ที่จะใช้สำหรับข้อความผิดพลาดเช่น wc -l "$file"จะพิมพ์ชื่อไฟล์ที่เราไม่ต้องการที่นี่และจะทำงานwcแม้ว่าจะไม่สามารถเปิดไฟล์ได้ $xถูกส่งออกไปfind( x=10 find...) shที่ตัวเองส่งผ่านไปยัง
find: -readable: unknown primary or operator.
bashที่ไม่ได้ลงไป bashเป็นเพียงตัวแปลบรรทัดคำสั่ง แต่เป็นfindการนำไปใช้งาน -readableเป็นส่วนขยายของ GNU ไม่สามารถใช้ได้ใน OS / findX ใช้เพื่อ จำกัด ไฟล์ที่สามารถอ่านได้เท่านั้น (คุณจะไม่สามารถนับจำนวนบรรทัดสำหรับไฟล์ที่อ่านไม่ได้) คุณสามารถละเว้นมันสำหรับอันแรกจากนั้นคุณจะได้รับข้อความแสดงข้อผิดพลาดเมื่อเปิดไฟล์สำหรับwcไฟล์ที่ไม่สามารถอ่านได้
เพื่อความสมบูรณ์นอกจาก AWK คุณยังสามารถใช้ GNU sed เพื่อให้ได้ผลลัพธ์เดียวกัน:
find . -type f -exec sed 11q1 '{}' ';' -exec echo rm -f '{}' ';'
ซึ่งส่งผลให้บรรทัดคำสั่งที่รัดกุมขึ้นอีกเล็กน้อย
คำอธิบาย
11 - is the address, i.e. "the eleventh line"
q - is for _q_uit (abort the execution)
1 - is the exit code parameter for q (GNU sed extension)
shคืออะไร 2.wc -l < "$file"เร็วกว่าwc -l "$file"ไหม 3. sh จะทราบค่าของวิธี$x, ซึ่งถูกกำหนดในการเรียก Bash shell ได้อย่างไร?