ด้วยsed
คุณอาจทำ:
sed '24q;1,5d;12,18d' <infile >outfile
... head
อาจจะเป็นทางออกที่มีประสิทธิภาพมากขึ้นอาจจะมีกับ ดอนได้แสดงให้เห็นแล้วว่ามันอาจทำงานได้ดีมาก แต่ฉันก็เล่นกับมันเช่นกัน บางสิ่งที่คุณอาจทำเพื่อจัดการกรณีเฉพาะนี้:
for n in 5 6 7 6
do head -n"$n" >&"$((1+n%2))"
done <infile >outfile 2>/dev/null
... ซึ่งจะเรียกhead
4 ครั้งที่เขียนไปยังoutfile
หรือ/dev/null
ขึ้นอยู่กับว่าค่าของการวนซ้ำ$n
นั้นเป็นจำนวนคู่หรือคี่
สำหรับกรณีทั่วไปมากขึ้นฉันเอาก้อนกรวดนี้มารวมกันจากสิ่งอื่น ๆ ที่ฉันมีอยู่แล้ว:
somehead()(
### call it like:
### somehead -[repeat] [-][numlines]* <infile >outfile
set -e -- "${1#-}" "$@" #-e for arg validation
r=; cd -- "${TMP:-/tmp}" #go to tmp
dd bs=4096 of="$$$$" <&4 2>&3 & #dd <in >tmpfile &bg
until [ -s "$$$$" ]; do :; done #wait while tmpfile empty
exec <"$$$$" 4<&-; rm "$$$$" #<tmpfile; rm tmpfile
[ "$3${1}0" -ne "$3${2#?}0" ] || #validate args - chk $1
shift "$(((r=-${1:--1})||1))"; shift #shift 1||2
while [ "$(((r+=(_n=1))-1))" -ne 0 ] && #while ! $rptmax &&
IFS= read -r l && # ! EOF &&
printf "%.$(($1>0?${#l}+1:0))s" "$l # ? printf do
"; do for n do [ "${n#-}" -gt 0 ] || exit #args all -[nums>0]
head "-n$((${n#-}-_n))" >&"$((n>(_n=0)?1:3))" #head -n?$1 >?[+-]
done; done #done and done
) 4<&0 3>/dev/null #4<for dd 3>for head
สิ่งนี้สามารถทำสิ่งที่คุณต้องการ:
seq 100 | somehead -1 -5 6 -7 6
... ที่พิมพ์ ...
6
7
8
9
10
11
19
20
21
22
23
24
คาดว่าหาเรื่องเป็นครั้งแรกที่จะทำซ้ำนับนำหน้าด้วยหรือความล้มเหลวที่เพียง-
-
หากมีการนับจำนวนมันจะทำซ้ำรูปแบบของเส้นที่กำหนดใน args ต่อไปนี้หลาย ๆ ครั้งตามที่ระบุและหยุดทันทีที่ทำเช่นนั้น
สำหรับหาเรื่องว่าต่อไปนี้มันจะแปลความหมายเชิงลบจำนวนเต็มแต่ละคนที่จะแสดงให้เห็นเป็นเส้นนับซึ่งควรจะเขียนไปและเป็นจำนวนเต็มบวกเพื่อบ่งชี้ถึงการนับบรรทัดซึ่งควรจะเขียนไป/dev/null
stdout
ดังนั้นในตัวอย่างข้างต้นจะพิมพ์ 5 สายแรกที่จะ/dev/null
ต่อไป 6 stdout
, 7 ถัดไป/dev/null
อีกครั้งและอีก 6 stdout
อีกครั้งเพื่อ เมื่อมาถึงจุดสุดท้ายของ args และกรณืเต็มที่ผ่านการ-1
นับซ้ำมันก็หยุด ถ้าหาเรื่องครั้งแรกที่เคยเป็น-2
มันจะได้ทำซ้ำกระบวนการอีกครั้งหรือถ้า-
นานเท่าที่จะทำได้
สำหรับแต่ละวงหาเรื่องwhile
วงรอบจะถูกประมวลผลครั้งเดียวผ่าน ที่ด้านบนของแต่ละวงบรรทัดแรกจากถูกอ่านในตัวแปรเปลือกstdin
$l
สิ่งนี้มีความจำเป็นเพราะwhile head </dev/null; do :; done
จะทำซ้ำอย่างไม่มีกำหนด - head
บ่งบอกถึงการกลับมาเมื่อไฟล์ถึงจุดสิ้นสุด ดังนั้นการตรวจสอบกับ EOF จึงมีความมุ่งมั่นread
และprintf
จะเขียน$l
รวมถึงการขึ้นบรรทัดใหม่ต่อstdout
เมื่ออาร์กิวเมนต์ที่สองเป็นจำนวนเต็มบวก
การread
ตรวจสอบจะทำให้เกิดความซับซ้อนของลูปเพียงเล็กน้อยเพราะทันทีหลังจากที่ลูปอื่นถูกเรียก - for
ลูปที่วนซ้ำข้าม args 2-$#
ดังที่แสดงไว้$n
สำหรับการวนซ้ำของwhile
ลูปพาเรนต์แต่ละครั้ง ซึ่งหมายความว่าสำหรับการทำซ้ำแต่ละครั้งอาร์กิวเมนต์แรกจะต้องลดค่าลงจากค่าที่ระบุในบรรทัดคำสั่ง แต่ค่าอื่น ๆ ทั้งหมดควรเก็บค่าดั้งเดิมไว้ดังนั้นค่าของตัว$_n
ทำเครื่องหมาย var จะถูกลบออกจากกัน ค่ามากกว่า 0 สำหรับ ARG แรก
ซึ่งถือว่าเป็นลูปหลักของฟังก์ชั่น แต่ส่วนใหญ่ของรหัสอยู่ที่ด้านบนและมีวัตถุประสงค์เพื่อเปิดใช้งานฟังก์ชั่นในการบัฟเฟอร์สะอาดแม้ท่อเป็นอินพุต วิธีนี้ใช้งานได้โดยเรียกพื้นหลังdd
เพื่อคัดลอกลงใน tmpfile บนเอาต์พุตที่ขนาดบล็อก 4k ต่อชิ้น จากนั้นฟังก์ชั่นจะตั้งค่าลูปการถือ - ซึ่งเกือบจะไม่สมบูรณ์แม้แต่รอบเดียว - เพื่อให้แน่ใจว่าdd
อย่างน้อยหนึ่งการเขียนไปยังไฟล์ก่อนที่ฟังก์ชั่นนั้นจะแทนที่ stdin ของมันด้วยไฟล์ descriptor ที่เชื่อมโยงกับ tmpfile และ หลังจากนั้นยกเลิกการเชื่อมโยงไฟล์ด้วยทันทีrm
. สิ่งนี้ช่วยให้ฟังก์ชั่นประมวลผลสตรีมได้อย่างน่าเชื่อถือโดยไม่ต้องใช้กับดักหรือทำความสะอาด - ทันทีที่ฟังก์ชั่นเปิดตัวมันอ้างสิทธิ์ใน fd tmpfile จะหยุดอยู่เพราะลิงก์ระบบไฟล์ที่ระบุชื่อเท่านั้นถูกลบไปแล้ว
head
และtail
? ถ้าเป็นเช่นนั้นทางออกของคุณดีที่สุดที่คุณสามารถทำได้ หากคุณได้รับอนุญาตให้ใช้โปรแกรมอื่นsed
หรือawk
อาจอนุญาตให้ใช้โซลูชันที่ดีกว่า (เช่นมีการเรียกใช้กระบวนการน้อยลง)