วิธีการรับพฤติกรรมผกผันสำหรับ "หาง" และ "หัว"


55

มีวิธีการhead/ tailเอกสารและรับเอาท์พุทย้อนกลับ; เพราะคุณไม่ทราบว่ามีเอกสารกี่บรรทัด?

คือฉันต้องการรับทุกอย่าง แต่ 2 บรรทัดแรกfoo.txtเพื่อต่อท้ายเอกสารอื่น

คำตอบ:


57

คุณสามารถใช้สิ่งนี้เพื่อตัดสองบรรทัดแรก :

tail -n +3 foo.txt

และนี่เพื่อตัดสองบรรทัดสุดท้าย :

head -n -2 foo.txt

(สมมติว่าไฟล์ลงท้ายด้วย\nหลัง)


เช่นเดียวกับการใช้มาตรฐานtailและheadการดำเนินการเหล่านี้ไม่ทำลาย ใช้>out.txtหากคุณต้องการเปลี่ยนเส้นทางไปยังไฟล์ใหม่:

tail -n +3 foo.txt >out.txt

ในกรณีที่out.txtมีอยู่แล้วมันจะเขียนทับไฟล์นี้ ใช้>>out.txtแทนถ้าคุณอยากจะได้ผลผลิตต่อท้าย>out.txtout.txt


3
"หัว\nอีกครั้งเมื่อไฟล์ลงท้ายด้วย" .. มันใช้งานได้สำหรับจำนวนเต็มลบทั้งหมดนอกเหนือจาก-n -0ที่จะส่งคืนอะไรเลยเช่นเดียวกับที่-n 0จะใช้ (ใช้: หัว (coreutils GNU) 7.4) ... อย่างไรก็ตามเมื่อมีการติดตาม\nอยู่-n -0จะพิมพ์ เป็นอาจจะคาดหวังจาก-คือ มันพิมพ์ไฟล์ทั้งหมด ... ดังนั้นจึงใช้งานได้สำหรับค่าลบที่ไม่ใช่ศูนย์ทั้งหมด .. แต่-0ล้มเหลวเมื่อไม่มีการติดตาม\n
Peter.O

@fred: แปลกจริง ๆ ... (เหมือนกับ 8.12 ที่นี่)
Stéphane Gimenez

การดำเนินการนี้เป็นอันตรายหรือไม่? ฉันต้องการคัดลอกค่าผกผันของสองบรรทัดแรกของเอกสารไปยังอีกอันหนึ่งหรือไม่?
chrisjlee

@Chris: ไม่พวกเขาเพียงพิมพ์ผลที่ "เอาท์พุทมาตรฐาน" ซึ่งมักจะเชื่อมต่อกับเทอร์มินัล ฉันได้เพิ่มรายละเอียดเกี่ยวกับวิธีการเปลี่ยนเส้นทางผลลัพธ์ไปยังบางไฟล์
Stéphane Gimenez

7
head -n -2ไม่ได้POSIX เข้ากันได้
l0b0

9

หากคุณต้องการทั้งหมด แต่แรก N-1 เส้นโทรที่มีจำนวนของเส้นtail +N(ตัวเลขคือจำนวนของบรรทัดแรกที่คุณต้องการเก็บไว้เริ่มต้นที่ 1 คือ +1 หมายถึงเริ่มต้นที่ด้านบน +2 หมายถึงข้ามหนึ่งบรรทัดและอื่น ๆ )

tail -n +3 foo.txt >>other-document

ไม่มีวิธีพกพาที่ง่ายดายในการข้ามบรรทัด N สุดท้าย GNU headช่วยให้เป็นของคู่ของhead -n +N tail -n +Nมิฉะนั้นหากคุณมีtac(เช่น GNU หรือ Busybox) คุณสามารถรวมกับหาง:

tac | tail -n +3 | tac

เป็นไปได้ว่าคุณสามารถใช้ตัวกรอง awk (ยังไม่ทดลอง):

awk -vskip=2 '{
    lines[NR] = $0;
    if (NR > skip) print lines[NR-skip];
    delete lines[NR-skip];
}'

หากคุณต้องการที่จะลบไม่กี่บรรทัดสุดท้ายออกจากไฟล์ขนาดใหญ่คุณสามารถกำหนดไบต์ offset ddของชิ้นส่วนที่จะตัดทอนจากนั้นทำการตัดกับ

total=$(wc -c < /file/to/truncate)
chop=$(tail -n 42 /file/to/truncate | wc -c)
dd if=/dev/null of=/file/to/truncate seek=1 bs="$((total-chop))"

คุณไม่สามารถตัดไฟล์ในตอนต้นได้แม้ว่าคุณจะต้องการลบไฟล์ขนาดใหญ่สองสามบรรทัดแรกคุณสามารถย้ายเนื้อหาไปมาได้


ในบางระบบ (เช่น Linux ที่ทันสมัย) คุณสามารถตัดทอน (ยุบ) ไฟล์ที่จุดเริ่มต้น แต่โดยปกติจะเป็นจำนวนที่มีขนาดบล็อก FS หลายเท่า (ซึ่งไม่ค่อยมีประโยชน์ในกรณีนี้)
Stéphane Chazelas

3

จากtailหน้าคน (GNU tailนั่นคือ):

-n, --lines=K
   output the last K lines, instead of the last 10; or use -n +K to
   output lines starting with the Kth

ดังนั้นต่อไปนี้ควรผนวกทั้งหมดยกเว้น 2 บรรทัดแรกของsomefile.txtถึงanotherfile.txt:

tail --lines=+3 somefile.txt >> anotherfile.txt

3

ในการลบบรรทัดแรก n บรรทัด GNU sed สามารถใช้งานได้ ตัวอย่างเช่นถ้า n = 2

sed -n '1,2!p' input-file

!หมายถึง "ยกเว้นช่วงเวลานี้" อย่างที่คุณสามารถจินตนาการได้ผลลัพธ์ที่ซับซ้อนมากขึ้นเช่น

sed -n '3,5p;7p'

ที่จะแสดงบรรทัด 3,4,5,7 พลังงานมากขึ้นมาจากการใช้นิพจน์ทั่วไปแทนที่อยู่

ข้อ จำกัด คือต้องทราบหมายเลขบรรทัดล่วงหน้า


1
ทำไมไม่เพียงsed 1,2d? ง่ายกว่าปกติดีกว่า นอกจากนี้ไม่มีสิ่งใดในตัวอย่างของคุณเฉพาะ GNU Sed; คำสั่งของคุณทุกคนใช้มาตรฐานคุณลักษณะของ POSIX Sed
สัญลักษณ์แทน

1

คุณสามารถใช้diffเพื่อเปรียบเทียบผลลัพธ์ของhead/ tailกับไฟล์ต้นฉบับแล้วลบสิ่งที่เหมือนกันดังนั้นจึงได้รับการผกผัน

diff --unchanged-group-format='' foo.txt <(head -2 foo.txt)

1

ในขณะที่tail -n +4การส่งออกไฟล์เริ่มต้นที่บรรทัดที่ 4 (ทั้งหมดยกเว้น 3 บรรทัดแรก) เป็นแบบมาตรฐานและพกพาได้ไฟล์headคู่ของมัน( head -n -3ทั้งหมดยกเว้น 3 บรรทัดสุดท้าย) ไม่ใช่

พกพาคุณจะทำ:

sed '$d' | sed '$d' | sed '$d'

หรือ:

sed -ne :1 -e '1,3{N;b1' -e '}' -e 'P;N;D'

(ระวังว่าในบางระบบที่sedมีพื้นที่รูปแบบที่มีขนาด จำกัด ซึ่งไม่ได้ปรับเป็นค่าขนาดใหญ่n)

หรือ:

awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'

1
{   head -n2 >/dev/null
    cat  >> other_document
}   <infile

หาก<infileเป็นlseek()ไฟล์ปกติที่สามารถใช้งานได้แล้วใช่โดยทั้งหมดรู้สึกฟรี ข้างต้นเป็นโครงสร้างที่รองรับ POSIXly อย่างสมบูรณ์


0

วิธีการของฉันคล้ายกับ Gilles แต่ฉันแค่ย้อนกลับไฟล์ด้วย cat และ pipe ที่มีคำสั่ง head

tac -r thefile.txt | ส่วนหัว thisfile.txt (แทนที่ไฟล์)


0

หวังว่าฉันเข้าใจความต้องการของคุณชัดเจน

คุณมีหลายวิธีในการดำเนินการตามคำขอของคุณ:

tail -n$(expr $(cat /etc/passwd|wc -l) - 2) /etc/passwd

โดยที่/ etc / passwdเป็นไฟล์ของคุณ

วิธีที่ 2 อาจเป็นประโยชน์หากคุณมีไฟล์ขนาดใหญ่:

my1stline=$(head -n1 /etc/passwd)
my2ndline=$(head -n2 /etc/passwd|grep -v "$my1stline")
cat /etc/passwd |grep -Ev "$my1stline|$my2ndline"

0

โซลูชันสำหรับ BSD (macOS):

ลบ 2 บรรทัดแรก:

tail -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

ลบ 2 บรรทัดสุดท้าย:

head -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

... ไม่ค่อยสง่า แต่ทำหน้าที่ให้สำเร็จ!

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