การป้อนข้อมูล:
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
ยังไม่ได้เกินในlines
file
#!/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
สิ่งนี้ใช้printf
builtin; รหัสรูปแบบ%.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'