วิธีรับบรรทัดแรกของไฟล์ในสคริปต์ทุบตี?


249

ฉันต้องใส่ตัวแปร bash ในบรรทัดแรกของไฟล์ ฉันเดาว่าเป็นคำสั่ง grep แต่มีวิธี จำกัด จำนวนบรรทัดหรือไม่?

คำตอบ:


397

headใช้บรรทัดแรกจากไฟล์และ-nพารามิเตอร์สามารถใช้เพื่อระบุจำนวนบรรทัดที่จะแตก:

line=$(head -n 1 filename)

3
อย่างมีนัยสำคัญค่าใช้จ่ายมากกว่าreadวิธีการ $()แยกออกจาก subshell และการใช้คำสั่งภายนอก (คำสั่งภายนอกใด ๆ ) หมายความว่าคุณกำลังเรียกexecve()ใช้ตัวเรียกใช้ตัวเชื่อมโยงและตัวโหลด (ถ้าใช้ไลบรารีที่ใช้ร่วมกันซึ่งมักเป็นกรณี) ฯลฯ
Charles Duffy

2
มันอาจจะเป็นแม้สั้น:line="$(head -1 FILENAME)"
Nikolay

3
และยัง:line=`head -1 FILENAME`
Shai Alon

backticks ที่อยู่รอบ ๆhead...เปิด subshell เหมือน$()หรือไม่?
Jaime Hablutzel

@ JaimeHablutzel ใช่พวกเขาเป็นสิ่งเดียวกันแม้ว่าโดยส่วนตัวแล้วฉันจะพบว่า$()ไวยากรณ์ดูง่ายกว่าและเห็นคุณค่าของความกระจ่างชัดยิ่งขึ้น gnu.org/software/bash/manual/html_node/…
Joseph Sikorski

61

หากต้องการอ่านบรรทัดแรกโดยใช้ bash ให้ใช้readคำสั่ง เช่น

read -r firstline<file

firstline จะเป็นตัวแปรของคุณ (ไม่จำเป็นต้องมอบหมายให้คนอื่น)


1
@sorin cat ... | read VARจะล้มเหลวในเชลล์ส่วนใหญ่ (ทั้งหมดยกเว้นzshเท่าที่ฉันรู้) เพราะแต่ละคอมโพเนนต์ในไพพ์จะทำงานในเชลล์ย่อยแยกกัน ความหมายที่$VARจะถูกตั้งค่าใน subshell (ที่หยุดอยู่ทันทีที่ไพพ์ไลน์เสร็จสิ้นการดำเนินการ) แทนที่จะอยู่ในเชลล์ที่เรียกใช้ คุณสามารถหลีกเลี่ยงปัญหานี้ได้ด้วยread VAR <<EOF\n$(cat ...)\nEOF(โดยที่แต่ละ\nบรรทัดขึ้นบรรทัดใหม่)
zrajm

@ โซรินcatเป็นค่าใช้จ่ายที่บริสุทธิ์ มีประสิทธิภาพมากขึ้นเพื่อread -r var <fileกว่าcat file | readแต่อย่างใดแม้ถ้าหลังไม่ได้ล้มเหลวด้วยเหตุผลที่อธิบายไว้ในBashFAQ #
ชาร์ลส์ดัฟฟี่

... หากคุณกำลังทำอะไรที่เกี่ยวข้องมากกว่าcatนี้read -r var < <(otherprog ...)
ชาร์ลส์ดัฟฟี่

14

พอเพียงนี้และเก็บบรรทัดแรกของfilenameในตัวแปร$line:

read -r line < filename

ฉันก็ชอบawkสิ่งนี้:

awk 'NR==1 {print; exit}' file

ในการจัดเก็บบรรทัดให้ใช้var=$(command)ไวยากรณ์ ในกรณีline=$(awk 'NR==1 {print; exit}' file)นี้

หรือแม้กระทั่งsed:

sed -n '1p' file

line=$(sed -n '1p' file)ด้วยเทียบเท่า


ดูตัวอย่างเมื่อเราป้อนreadด้วยseq 10นั่นคือลำดับของตัวเลขจาก 1 ถึง 10:

$ read -r line < <(seq 10) 
$ echo "$line"
1

$ line=$(awk 'NR==1 {print; exit}' <(seq 10))
$ echo "$line"
1

1
sed '1!d;q'(หรือsed -n '1p;q') จะเลียนแบบawkตรรกะของคุณและป้องกันการอ่านเพิ่มเติมลงในไฟล์ เพราะเราต้องการแค่บรรทัดแรกเท่านั้นเราสามารถโกงsed qหรือawk '1;{exit}'หรือแม้แต่grep -m1 ^(รหัสน้อยกว่าตรรกะที่จำเป็นเดียวกัน) (นี่ไม่ใช่คำตอบสำหรับข้อสงสัย downvote)
Adam Katz

@ AdamKatz มันเป็นวิธีที่ดีมากขอบคุณ! ฉันพบคนgrepที่ฉลาดมาก แน่นอนเราสามารถพูดhead -n 1 fileได้
fedorqui 'ดังนั้นหยุดการทำร้าย'

ใช่head -n1จะเร็วขึ้น (ไบนารีที่เล็กกว่าสำหรับโหลด) และreadจะเร็วที่สุด (ไม่มีไบนารีสำหรับโหลดนั่นคือบิวด์อิน) ฉันชอบโดยเฉพาะอย่างยิ่งgrep -m1 --color .เมื่อฉันเพิ่งพิมพ์บรรทัดแรกเพราะมันจะทำให้สีของเส้นเกินไปทำให้ดีสำหรับส่วนหัวของตาราง
Adam Katz

12
line=$(head -1 file)

จะทำงานได้ดี (ตามคำตอบก่อนหน้า) แต่

line=$(read -r FIRSTLINE < filename)

จะเร็วขึ้นเล็กน้อยเช่นเดียวกับreadคำสั่ง bash ในตัว


21
วิธีที่สองไม่ทำงานตามที่เขียนไว้เพราะreadไม่ได้พิมพ์อะไรเลย ( lineเว้นว่างไว้) และดำเนินการใน subshell (ดังนั้นFIRSTLINEได้รับการตั้งค่าเป็นบรรทัดแรก แต่เฉพาะใน subshell ดังนั้นจึงไม่สามารถใช้งานได้ในภายหลัง) วิธีแก้ปัญหา: ใช้เพียงread -r line <filename
Gordon Davisson

5

เพียงechoรายการแรกของไฟล์ต้นฉบับของคุณลงในไฟล์เป้าหมายของคุณ

echo $(head -n 1 source.txt) > target.txt

3
ซึ่งhead -n 1 source.txt > target.txtจะทำสิ่งเดียวกันให้สำเร็จ
YoYo

4

คำถามไม่ได้ถามว่าคำถามใดเร็วที่สุด แต่เพื่อเพิ่มคำตอบที่น่าเบื่อ -n '1p' ทำงานได้ไม่ดีเนื่องจากพื้นที่รูปแบบยังคงสแกนในไฟล์ขนาดใหญ่ จากความอยากรู้ฉันพบว่า 'หัว' ชนะเหนือความอดกลั้น:

# best:
head -n1 $bigfile >/dev/null

# a bit slower than head (I saw about 10% difference):
sed '1q' $bigfile >/dev/null

# VERY slow:
sed -n '1p' $bigfile >/dev/null
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.