การป้อนข้อมูล:
1
hgh
h2b
h4h
2
ok
koko
lkopk
3
uh
ju
nfjvn
4
ผลลัพธ์ที่คาดหวัง:
1
2
3
4
ดังนั้นฉันต้องมีค่า 1, 5, 9, 13 ของไฟล์ในไฟล์เอาต์พุต ทำอย่างไร
การป้อนข้อมูล:
1
hgh
h2b
h4h
2
ok
koko
lkopk
3
uh
ju
nfjvn
4
ผลลัพธ์ที่คาดหวัง:
1
2
3
4
ดังนั้นฉันต้องมีค่า 1, 5, 9, 13 ของไฟล์ในไฟล์เอาต์พุต ทำอย่างไร
คำตอบ:
ใช้ AWK:
awk '!((NR - 1) % 4)' input > output
หาวิธีการทำงานนี้เหลือเป็นแบบฝึกหัดสำหรับผู้อ่าน
NR % 4 == 1จะเป็น IMO ที่ชัดเจนมากขึ้น
การใช้split (GNU coreutils):
split -nr/1/4 input > output
-nสร้างCHUNKSไฟล์เอาต์พุตและCHUNKSเป็น
r/K/N ใช้การกระจายแบบโรบินแบบกลมและส่งเอาต์พุต Kth of N ไปยัง stdout เท่านั้นโดยไม่ต้องแยกบรรทัด / บันทึกด้วย GNU sed:
sed '1~4!d' < input > output
ด้วยมาตรฐานsed:
sed -n 'p;n;n;n' < input > output
ด้วย1และ4ใน$nและ$iตัวแปร:
sed "$n~$i!d" # GNU only
awk -v n="$n" -v i="$i" 'NR >= n && (NR % i) == (n % i)'
การเพิ่มวิธีการแก้ปัญหา Perl บังคับ:
perl -ne 'print if $. % 4 == 1' input > output
Python version เพื่อความสนุกสนาน:
with open('input.txt') as f:
for i, line in enumerate(f.readlines()):
if i%4 == 0:
print(line.strip())
enumerate(f)ควรจะสามารถทำงานได้ในขณะที่ใช้หน่วยความจำน้อยลง
readlines(จึงทำให้ไฟล์ทั้งหมดในหน่วยความจำ slurping) คุณสามารถใช้f.readlines()[::4]เพื่อรับทุกบรรทัดที่สี่ print(''.join(f.readlines()[::4]))ดังนั้นคุณสามารถใช้
POSIX sed: วิธีนี้ใช้ sedix posixly และสามารถเรียกใช้ได้ทุกที่หรืออย่างน้อย seds ที่เคารพ posix
$ sed -ne '
/\n/!{
H;s/.*//;x
}
:loop
$bdone
N;s/\n/&/4
tdone
bloop
:done
s/.//;P
' input.file
อีกประการหนึ่งคือการสร้างรหัส sed แบบเป็นโปรแกรมเพื่อวัตถุประสงค์ในการปรับขยาย:
$ code=$(yes n | head -n 4 | paste -sd\; | sed s/n/p/)
$ sed -ne "$code" input.file
Perl: เราเติมอาร์เรย์ A จนกว่าจะมีขนาด 4 จากนั้นเราพิมพ์องค์ประกอบแรกและล้างอาร์เรย์
$ perl -pe '
$A[@A] = @A ? <> : $_ while @A < 4;
$_ = (splice @A)[0];
' input.file
โทรด้วยscriptname filename skip(4 ในกรณีของคุณ) มันทำงานได้โดยการiterลากเส้นจากด้านบนของไฟล์จากนั้นจึงส่งออกล่าสุดเท่านั้น จากนั้นจะเพิ่มขึ้นiterโดยskipsและซ้ำตราบใดที่ค่าของiterยังไม่ได้เกินในlinesfile
#!/bin/bash
file="$1"
lines=`wc -l < "$file"`
skips="$2" || "4"
iter=1
while [ "$iter" -le "$lines" ]; do
head "$file" -n $iter | tail -n 1
iter=$(( $iter + $skips ))
done
Pure Bash:
mapfile -t lines < input
for (( i=0; i < ${#lines[@]}; i+=4 ))
do printf "%s\n" "${lines[$i]}"
done
mapfileเป็น buildin ที่เพิ่มใน Bash 4 ซึ่งอ่านอินพุตมาตรฐานลงในอาร์เรย์ชื่อที่นี่linesพร้อมหนึ่งบรรทัดต่อรายการ -tตัวเลือกแถบบรรทัดใหม่สุดท้าย
หากคุณต้องการที่จะพิมพ์บรรทัดที่สี่ทุกเริ่มต้นจากสาย 4 แล้วคุณสามารถทำในคำสั่งอย่างใดอย่างหนึ่งโดยใช้mapfile's ตัวเลือกการเรียกกลับซึ่งไหลรหัสให้ทุกสายจำนวนมากกับช่วงเวลาที่กำหนดโดย-C -cดัชนีอาร์เรย์ปัจจุบันและบรรทัดถัดไปที่จะถูกกำหนดให้กับรหัสเป็นอาร์กิวเมนต์
mapfile -t -c4 -C 'printf "%.0s%s\n"' < input
สิ่งนี้ใช้printfbuiltin; รหัสรูปแบบ%.0sระงับอาร์กิวเมนต์แรก (ดัชนี) ดังนั้นจะพิมพ์เฉพาะบรรทัด
คุณสามารถใช้คำสั่งเดียวกันเพื่อพิมพ์ทุก ๆ บรรทัดที่สี่โดยเริ่มจากบรรทัดที่ 1, 2 หรือ 3 แต่คุณต้องเพิ่มบรรทัดที่ 3, 2 หรือ 1 inputก่อนที่จะป้อนมันmapfileซึ่งฉันคิดว่าเป็นปัญหามากกว่าที่ควรจะเป็น .
สิ่งนี้ยังใช้งานได้:
mapfile -t lines < input
printf "%s%.0s%.0s%.0s\n" "${lines[@]}"
นี่printfกินสี่รายการของอาร์เรย์ในเวลาเพียงพิมพ์ครั้งแรกและการกระโดดข้ามอีกสามด้วยlines %.0sฉันไม่ชอบสิ่งนี้เนื่องจากคุณต้องเล่นซอกับสตริงรูปแบบด้วยตนเองสำหรับช่วงเวลาหรือจุดเริ่มต้นที่แตกต่างกัน
sed -n '1~4p'