วิธีที่รวดเร็วในการลบไฟล์ที่มีเส้นน้อยกว่า x


10

วิธีที่รวดเร็วและไม่ซับซ้อนเกินไปในการลบไฟล์ทั้งหมดในไดเรกทอรีที่มีความยาว x บรรทัดในทุบตีคืออะไร

คำตอบ:


10

นี่เป็นวิธีแก้ปัญหา POSIX ที่ควรเข้าใจง่าย:

find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;

เช่นเดียวกับคำตอบของสเตฟานให้ลบechoความสุขเมื่อมีสิ่งที่จะถูกลบออก


คำอธิบายเขียนขึ้นสำหรับผู้ที่ยังใหม่กับ Unix / Linux:

จุด.แสดงถึงไดเรกทอรีปัจจุบัน 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

5

สมมติว่าการ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หากมีความสุข


1. สุดท้ายshคืออะไร 2. wc -l < "$file"เร็วกว่าwc -l "$file"ไหม 3. sh จะทราบค่าของวิธี$x, ซึ่งถูกกำหนดในการเรียก Bash shell ได้อย่างไร?

3
@tomas สุดท้ายshคือสิ่งที่เกิดขึ้นในสคริปต์แบบอินไลน์ของ$0ที่จะใช้สำหรับข้อความผิดพลาดเช่น wc -l "$file"จะพิมพ์ชื่อไฟล์ที่เราไม่ต้องการที่นี่และจะทำงานwcแม้ว่าจะไม่สามารถเปิดไฟล์ได้ $xถูกส่งออกไปfind( x=10 find...) shที่ตัวเองส่งผ่านไปยัง
Stéphane Chazelas

ขอบคุณ! แต่ฉันเดาว่าข้อผิดพลาดที่ฉันได้รับบน OSX นี้หมายความว่าเวอร์ชั่น Bash ของฉันไม่รองรับแฟล็ก -readable find: -readable: unknown primary or operator.
durrrutti

1
@durrrutti bashที่ไม่ได้ลงไป bashเป็นเพียงตัวแปลบรรทัดคำสั่ง แต่เป็นfindการนำไปใช้งาน -readableเป็นส่วนขยายของ GNU ไม่สามารถใช้ได้ใน OS / findX ใช้เพื่อ จำกัด ไฟล์ที่สามารถอ่านได้เท่านั้น (คุณจะไม่สามารถนับจำนวนบรรทัดสำหรับไฟล์ที่อ่านไม่ได้) คุณสามารถละเว้นมันสำหรับอันแรกจากนั้นคุณจะได้รับข้อความแสดงข้อผิดพลาดเมื่อเปิดไฟล์สำหรับwcไฟล์ที่ไม่สามารถอ่านได้
Stéphane Chazelas

@ StéphaneChazelasคำตอบนี้ช่างยุ่งยากเหลือเกินที่ฉันยังสงสัยอยู่ว่า: ฉันคิดถึงเคสที่มีคำตอบไหม? :)
สัญลักษณ์แทน

2

เพื่อความสมบูรณ์นอกจาก 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) 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.