ลบ n ไบต์แรกของไฟล์


32

ฉันมีปัญหามากและวิธีแก้ไขทั้งหมดที่ฉันจินตนาการได้นั้นซับซ้อน จากประสบการณ์ UNIX / Linux ของฉันต้องมีวิธีที่ง่าย

ฉันต้องการที่จะลบ 31 /foo/ไบต์แรกของแต่ละแฟ้มใน แต่ละไฟล์มีความยาวเพียงพอ ฉันแน่ใจว่าใครบางคนจะส่งมอบวิธีแก้ปัญหาที่ง่ายอย่างเหลือเชื่อให้กับฉันฉันไม่สามารถจินตนาการได้ อาจจะตกใจ


2
โซลูชัน awk / sed / ed จะเป็นแบบบรรทัดดังนั้นถ้าคุณไม่ทราบว่าบรรทัดแรกจะมีอักขระอย่างน้อย 31 ตัวดังนั้นจึงเกิดปัญหาแทรกซ้อนขึ้น
glenn jackman

คำตอบ:


28
for file in /foo/*
do
  if [ -f "$file" ]
  then
    dd if="$file" of="$file.truncated" bs=31 skip=1 && mv "$file.truncated" "$file"
  fi
done

หรือเร็วกว่านั้นด้วยคำแนะนำของ Gilles:

for file in /foo/*
    do
      if [ -f $file ]
      then
        tail +32c $file > $file.truncated && mv $file.truncated $file
      fi
    done

หมายเหตุ: Posix tail ระบุ "-c +32" แทนที่จะเป็น "+ 32c" แต่หางเริ่มต้นของ Solaris ไม่ชอบ:

   $ /usr/bin/tail -c +32 /tmp/foo > /tmp/foo1
    tail: cannot open input

/usr/xpg4/bin/tail ใช้ได้ทั้งซินแท็กซ์


1
การแนะนำddที่นี่เป็นงานมากเกินไปtailเหมาะสมกว่า (ง่ายกว่าและมีความเสี่ยงน้อยกว่าในการพิมพ์ผิดโดยไม่มีข้อความปลอมบน stderr)
Gilles 'หยุดชั่วร้าย'

คุณพูดถูก ฉันมักจะหลีกเลี่ยงคำสั่งที่ต้องการประมวลผลไฟล์ข้อความเมื่อประมวลผลอาจเป็นไบนารี แต่ "tail + 32c" จะทำงานที่นี่
jlliagre

1
@jlliagre: คุณได้เขียนcut ? (ไม่ควรที่จะเป็นหาง ... ASIS ก็ไม่ได้ทำงานสำหรับฉัน ...
Peter.O

แน่นอนว่ามันเป็นหาง ขออภัยเกี่ยวกับความไม่ตรงกัน
jlliagre

@jlliagre: บน Solaris คุณควรจะ/usr/xpg4/binไปข้างหน้าของ/usr/binคุณPATHหรือคุณจะติดอยู่ในต้นปี 1990 หลาย Unices (เช่น GNU, BusyBox) ไม่สนับสนุน+32cไวยากรณ์ในอดีตอีกต่อไปและใช้เพื่อหมายถึงไฟล์ที่เรียกว่า+32c(ตามที่ POSIX ต้องการ)
Gilles 'หยุดความชั่วร้าย'

12

คำสั่งต่อไปนี้ตัด 31 ไบต์แรกจาก$file(ใช้$file~เป็นสำเนาชั่วคราว):

dd if="$file" of="$file~" bs=1 skip=31
mv "$file~" "$file"

คุณจะต้องแสดงรายการหรือfindไฟล์ทั้งหมดภายใต้/foo/และดำเนินการทั้งสองด้านบนสำหรับทุก ๆ ที่$fileพบ


1
การสลับค่า bs และข้ามจะเพิ่มประสิทธิภาพ
jlliagre

10

tail -c +32เอาต์พุตอินพุตลบ 31 ไบต์แรก (ใช่แล้วอาร์กิวเมนต์จะถูกปิดโดยหนึ่ง) หากต้องการแก้ไขไฟล์ให้ใช้ฟองน้ำเป็นวงหรือถ้าคุณไม่มีไฟล์และไม่ต้องการรบกวนให้ทำงานในเชลล์:

for x in /foo/*; do tail -c +32 "$x" | sponge "$x"; done
for x in /foo/*; do tail -c +32 "$x" >"$x.new" && mv "$x.new" "$x"; done

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

mkdir /foo.tmp
cd /foo
for x in *; do tail -c +42 -- "$x" >"/foo.tmp/$x" && rm -- "$x"; done
mv /foo.tmp/* /foo
rmdir /foo.tmp

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


2

คุณสามารถใช้ Vim ในโหมด Ex:

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % เลือกทุกบรรทัด

  2. ! เรียกใช้คำสั่ง

  3. x บันทึกและปิด

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