การแปลงแท็บเป็นช่องว่างในไฟล์จำนวนมาก


11

ฉันมีไฟล์จำนวนมากที่มีแท็บเกลื่อนไปทั่วและฉันต้องการแปลงให้เป็นช่องว่าง ฉันรู้เกี่ยวกับexpandคำสั่ง แต่น่าเสียดายที่ฉันจะต้องพิมพ์ทุกไฟล์เดียวใช้มัน มีวิธีใดที่ง่ายกว่าในการทำเช่นนี้บน Linux?

คำตอบ:


12

ลองทำสิ่งต่อไปนี้:

find ./ -type f -exec sed -i 's/\t/ /g' {} \;

หากคุณต้องการช่องว่างสี่ลอง:

find ./ -type f -exec sed -i 's/\t/    /g' {} \;

ที่จะแทนที่แต่ละแท็บด้วยช่องว่างเดียว เนื่องจากบุคคลที่กล่าวถึงการใช้expandฉันถือว่า s / เขาต้องการการจัดตำแหน่งของข้อความที่เก็บรักษาไว้
garyjohn

คุณต้อง's/\t/ /g'แทนที่มากกว่าหนึ่งแท็บต่อบรรทัด
Daniel Andersson

1
ความเร็วที่เพิ่มขึ้นอย่างมากหากมีไฟล์จำนวนมากกำลังทำ " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (นั่นคือ " +" แทนที่จะเป็น " \;") ถ้าfindรุ่นรองรับมัน (และฉันไม่ได้พบกับรุ่นที่ไม่เป็นส่วนตัว แต่มันไม่ใช่มาตรฐาน POSIX ดังนั้นฉันเดาว่ามันอาจเกิดขึ้นได้ในบางระบบดู " -exec command {} +" ในคู่มือ) แทนที่จะเรียกใช้หนึ่งอินสแตนซ์sedสำหรับทุกไฟล์สิ่งนี้จะสร้างรายการอาร์กิวเมนต์ที่มีอาร์กิวเมนต์ชื่อไฟล์มากที่สุดเท่าที่ระบบรองรับ ( getconf ARG_MAX= 2097152 บนระบบของฉัน) เหมือนxargsและเปิดใช้sedกระบวนการน้อยลง
Daniel Andersson

6
หมายเหตุสำหรับผู้ใช้ Mac ที่พบสิ่งนี้: เวอร์ชันของ OS X sedไม่เข้าใจ\tลำดับการยกเว้นแท็บ [Ctrl]+V, [Tab]คุณสามารถแทนที่ด้วยอักขระแท็บตัวอักษรที่คุณสามารถใส่ในเปลือกโดย
Jeremy Banks กล่าวว่าบ้านอยู่

expandอาจดีกว่าsedสำหรับสิ่งนี้ตามที่อธิบายไว้ใน: stackoverflow.com/a/11094620/131824
David Weinraub

6

มีหลายวิธีในการทำเช่นนี้ นอกจากนี้ยังมีวิธีการยิงตัวเองมากมายในขณะที่ทำเช่นนี้หากคุณไม่ระวังหรือหากคุณยังใหม่กับ Linux ตามที่ปรากฏ สมมติว่าคุณสามารถสร้างรายการไฟล์ที่คุณต้องการแปลงไม่ว่าจะโดยการใช้อะไรที่ชอบfindหรือด้วยตนเองกับโปรแกรมแก้ไขเพียงแค่ไพพ์รายการนั้นลงในรายการต่อไปนี้

while read file
do
   expand "$file" > /tmp/expandtmp
   mv /tmp/expandtmp "$file"
done

วิธีหนึ่งที่คุณสามารถยิงด้วยเท้านั้นคือการพิมพ์ผิดเพื่อให้คุณหมุนไฟล์เปล่าให้กับชื่อไฟล์ทั้งหมดที่คุณระบุดังนั้นการลบเนื้อหาของไฟล์ทั้งหมดของคุณ ดังนั้นควรระมัดระวังและทดสอบสิ่งที่คุณทำก่อนในไฟล์ชุดเล็ก ๆ ที่คุณสำรองไว้


3
ทำให้mvเงื่อนไขเกี่ยวกับความสำเร็จของexpand:expand ... && mv ...
หยุดชั่วคราวจนกว่าจะมีประกาศเพิ่มเติม

อย่าลืมexpand -t 4ขยายแท็บเป็น 4 ช่องว่าง นอกจากนี้วิธีนี้สามารถสร้างการขึ้นบรรทัดใหม่ แต่อย่างอื่นมันใช้งานได้
mgold

3
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo สร้างตัวแปรแม่แบบ foo สำหรับแต่ละบรรทัดอินพุตดังนั้นคุณสามารถอ้างถึงอินพุตมากกว่าหนึ่งครั้ง

-print0และ-0บอกให้ทั้งสองคำสั่งใช้ \ 0 เป็นตัวคั่นบรรทัดแทน SPACE ดังนั้นคำสั่งนี้จะทำงานกับพา ธ ที่มีช่องว่าง


1
find -name \*.js -exec bash -c 'expand -t 4 "$0" | tee "$0"' {} \;

ข้อด้อย:
ไฟล์ที่มีขนาดใหญ่กว่าขนาดบัฟเฟอร์ของท่อ ( 64KB ) จะถูกตัดทอน

ข้อดี:
ไม่มีไฟล์ temp ที่
ใหญ่กว่าขนาดบัฟเฟอร์ของท่อถูกตัดทอน


0

สิ่งนี้ดีกว่า:

find . -name *.java ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

3
ทำไมสิ่งนี้ถึงดีกว่า ไม่ใช่ความคิดที่ดีที่จะใช้/tmp/eเพราะหากมีสิ่งอื่นใดที่ใช้ไฟล์นั้นสิ่งนี้จะทำให้ยุ่งเหยิง เช่นถ้าผู้ใช้สองคนต้องการใช้สิ่งนี้ในเวลาเดียวกัน
Kevin Panko

0

ฉันให้ปัญหานี้โดยคำนึงถึงข้อกำหนดต่อไปนี้:

  • กรองไฟล์ตามชื่อเพื่อดำเนินการกับไฟล์เช่น. cpp หรือ. json
  • รองรับการประมวลผลแบบขนาน ในกรณีที่มีไฟล์จำนวนมากสิ่งนี้สามารถช่วยเร่งความเร็วได้อย่างมาก
  • การแก้ปัญหาควรจะพอดีในหนึ่งบรรทัดเพื่อใช้งานง่าย

ความต้องการครั้งสุดท้ายเป็นสิ่งที่ยากที่สุดที่จะทำเพราะ "ขยาย" ไม่อนุญาตให้แก้ไขไฟล์ที่มีอยู่

ฉันคิดวิธีแก้ปัญหาต่อไปนี้ขึ้นมา:

find . -type f -regextype egrep -regex '.*\.(c|cpp|h|hpp)'  -print0 | xargs -0 -n 1 -P 10 -IFILE bash -c ' ( echo "Processing FILE..." && expand -t 4 "FILE" > /tmp/expand.$$ && mv /tmp/expand.$$ "FILE" ) || exit 255'

นี่คือคำอธิบายบางอย่าง:

  • "find" ค้นหาไฟล์ที่จะประมวลผล "-regextype egrep" อนุญาตให้กรองตามชื่อและนิพจน์ทั่วไปในรูปแบบ "egrep"
  • พารามิเตอร์ "-type f" ทำให้แน่ใจว่าเราจะจับคู่เฉพาะไฟล์ปกติไม่ใช่สำหรับไดเรกทอรีอินสแตนซ์หรืออย่างอื่นพิเศษ
  • พารามิเตอร์ "-regexp" คือนิพจน์ทั่วไปซึ่งตรงกับในกรณีนี้ไฟล์ใด ๆ ที่ลงท้ายด้วย. c, .cpp, .h หรือ. hpp (ชื่อทั้งหมดต้องตรงกันดังนั้น "file.c2" จะไม่ตรงกัน ซึ่งเป็นสิ่งที่เราต้องการ)
  • "-print0" สั่งให้ "find" เพื่อพิมพ์พา ธ ของไฟล์บนเอาต์พุตมาตรฐานด้วยอักขระ 0 ที่ส่วนท้ายของแต่ละพา ธ เมื่อใช้ร่วมกับตัวเลือก "-0" สำหรับ "xargs" จะอนุญาตให้ส่งชื่อที่มีรถส่งคืนจากเครื่องมือหนึ่งไปยังอีกเครื่องมือหนึ่ง (แม้ว่าจะเป็นสถานการณ์ที่ค่อนข้างหายาก ... )
  • xargs เริ่มต้นกระบวนการใหม่สำหรับแต่ละเส้นทาง ("-n 1") แต่อาจทำงานได้มากถึง 10 กระบวนการในแบบคู่ขนาน ("-P 10")
  • xargs ใช้นามแฝง "ไฟล์" เพื่อส่งผ่านแต่ละพา ธ ไฟล์ไปยังคำสั่งซึ่งเป็นสคริปต์ทุบตี
  • สคริปต์ทุบตีเรียก "ขยาย" และบันทึกผลลัพธ์ในไฟล์ชั่วคราวซึ่งชื่อมี ID กระบวนการปัจจุบัน ($$) เพื่อให้กระบวนการทั้งหมดทำงานแบบขนานที่ไฟล์ที่กำหนดใช้ไฟล์ชั่วคราวที่แตกต่างกัน
  • คำสั่งทั้งหมดใช้รูปแบบ (command1 && command2 && command3) เพื่อให้กระบวนการหยุดถ้าคำสั่งย่อยใด ๆ ส่งกลับข้อผิดพลาด
  • หากมีข้อผิดพลาดใด ๆ จากเครือข่าย "&&" ก่อนหน้าสคริปต์ทุบตีจะส่งคืนรหัสทางออก 255 ที่จะทำให้ xargs หยุดทันที
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.