ฉันมีคำสั่งตัวอย่างเช่น: echo "word1 word2"
. ฉันต้องการใส่ท่อ ( |
) และรับ word1 จากคำสั่ง
echo "word1 word2" | ....
ไม่รู้จะใส่ท่ออะไรหลัง
ฉันมีคำสั่งตัวอย่างเช่น: echo "word1 word2"
. ฉันต้องการใส่ท่อ ( |
) และรับ word1 จากคำสั่ง
echo "word1 word2" | ....
ไม่รู้จะใส่ท่ออะไรหลัง
คำตอบ:
Awk เป็นตัวเลือกที่ดีหากคุณต้องจัดการกับช่องว่างต่อท้ายเพราะมันจะดูแลคุณ:
echo " word1 word2 " | awk '{print $1;}' # Prints "word1"
Cut จะไม่ดูแลสิ่งนี้แม้ว่า:
echo " word1 word2 " | cut -f 1 -d " " # Prints nothing/whitespace
"ตัด" ที่นี่จะไม่พิมพ์อะไรเลย / เว้นวรรคเพราะสิ่งแรกก่อนเว้นวรรคคือช่องว่างอื่น
-F","
เพื่อแทนที่ตัวคั่นฟิลด์เริ่มต้น (ช่องว่าง) ด้วยลูกน้ำ
ไม่จำเป็นต้องใช้คำสั่งภายนอก Bash เองก็สามารถทำงานได้ สมมติว่า "word1 word2" คุณได้มาจากที่ไหนสักแห่งและเก็บไว้ในตัวแปรเช่น
$ string="word1 word2"
$ set -- $string
$ echo $1
word1
$ echo $2
word2
ตอนนี้คุณสามารถกำหนด $ 1 หรือ $ 2 ฯลฯ ให้กับตัวแปรอื่นได้หากต้องการ
stdin
. @Matt M. --
หมายถึงstdin
จึง$string
ถูกส่งต่อเป็นstdin
. stdin
เป็นช่องว่างแยกออกเป็นข้อโต้แย้ง$1
, $2
, $3
ฯลฯ - เช่นเดียวกับเมื่อทุบตีประเมินโปรแกรมการขัดแย้ง (เช่นการตรวจสอบ$1
, $2
ฯลฯ ) วิธีนี้จะได้ประโยชน์จากแนวโน้มเปลือกที่จะแยกstdin
ออกเป็นข้อโต้แย้งโดยอัตโนมัติลบความจำเป็นในการหรือawk
cut
set
ตั้งค่าอาร์กิวเมนต์เชลล์
word1=$(IFS=" " ; set -- $string ; echo $1)
ตั้งค่า IFS เพื่อรับรู้ช่องว่างระหว่างคำอย่างถูกต้อง ใส่วงเล็บเพื่อหลีกเลี่ยงการอุดตันเนื้อหาต้นฉบับจำนวน $ 1
string="*"
. แปลกใจ
ฉันคิดว่าวิธีหนึ่งที่มีประสิทธิภาพคือการใช้ bash arrays:
array=( $string ) # do not use quotes in order to allow word expansion
echo ${array[0]} # You can retrieve any word. Index runs from 0 to length-1
นอกจากนี้คุณสามารถอ่านอาร์เรย์โดยตรงในเส้นท่อ:
echo "word1 word2" | while read -a array; do echo "${array[0]}" ; done
echo " word1 word2 " | { read -a array ; echo ${array[0]} ; }
string="*"
. แปลกใจ
while
ไวยากรณ์เพื่อดึงทุกคำแรกในแต่ละบรรทัด มิฉะนั้นให้ใช้บุญทวีโฮม นอกจากนี้โปรดทราบว่าecho "${array[0]}"
มีการอ้างถึงเพื่อป้องกันการขยายตัวตามที่ gniourf-gniourf สังเกตเห็น
echo "word1 word2 word3" | { read first rest ; echo $first ; }
สิ่งนี้มีข้อดีที่ไม่ได้ใช้คำสั่งภายนอกและปล่อยให้ตัวแปร $ 1, $ 2 และอื่น ๆ เหมือนเดิม
$1, $2, …
ยังคงอยู่เป็นคุณสมบัติที่มีประโยชน์อย่างยิ่งสำหรับการเขียนสคริปต์!
หากคุณแน่ใจว่าไม่มีช่องว่างนำหน้าคุณสามารถใช้การแทนที่พารามิเตอร์ bash:
$ string="word1 word2"
$ echo ${string/%\ */}
word1
ระวังการหลบหนีพื้นที่เดียว ดูตัวอย่างรูปแบบการทดแทนเพิ่มเติมได้ที่นี่ หากคุณมี bash> 3.0 คุณยังสามารถใช้การจับคู่นิพจน์ทั่วไปเพื่อจัดการกับช่องว่างนำหน้าได้ - ดูที่นี่ :
$ string=" word1 word2"
$ [[ ${string} =~ \ *([^\ ]*) ]]
$ echo ${BASH_REMATCH[1]}
word1
คุณสามารถลอง awk
echo "word1 word2" | awk '{ print $1 }'
ด้วย awk มันง่ายมากที่จะเลือกคำที่คุณชอบ ($ 1, $ 2, ... )
%% *
นี่คือวิธีการแก้ปัญหาอื่นโดยใช้การขยายตัวพารามิเตอร์เปลือก ดูแลช่องว่างหลายช่องหลังคำแรก การจัดการช่องว่างหน้าคำแรกจำเป็นต้องมีการขยายเพิ่มเติมหนึ่งครั้ง
string='word1 word2'
echo ${string%% *}
word1
string='word1 word2 '
echo ${string%% *}
word1
%%
หมายลบการแข่งขันเป็นไปได้ที่ยาวที่สุดของ *
(เว้นวรรคตามด้วยหมายเลขของสิ่งที่ตัวละครอื่น ๆ ) ในท้ายstring
ส่วนหนึ่งของ
ฉันสงสัยว่าคำตอบยอดนิยมหลายข้อวัดได้อย่างไรในแง่ของความเร็ว ฉันทดสอบสิ่งต่อไปนี้:
1 @ mattbh's
echo "..." | awk '{print $1;}'
2 @ ghostdog74's
string="..."; set -- $string; echo $1
3 @ บุญทวีโฮมส์
echo "..." | { read -a array ; echo ${array[0]} ; }
และ4 @ boontawee-home's
echo "..." | { read first _ ; echo $first ; }
ฉันวัดด้วยเวลาของ Python ในสคริปต์ Bash ในเทอร์มินัล Zsh บน macOS โดยใช้สตริงทดสอบที่มีคำ 5 ตัวอักษร 215 คำ ทำการวัดแต่ละครั้ง 5 ครั้ง (ผลลัพธ์ทั้งหมดเป็น 100 ลูปดีที่สุด 3) และเฉลี่ยผลลัพธ์:
method time
--------------------------------
1. awk 9.2ms
2. set 11.6ms (1.26 * "1")
3. read -a 11.7ms (1.27 * "1")
4. read 13.6ms (1.48 * "1")
เยี่ยมมากผู้มีสิทธิเลือกตั้ง👏คะแนน (ณ วันที่เขียนนี้) ตรงกับความเร็วของการแก้ปัญหา!
read -a
เป็นเส้นประไม่ถูกต้อง)
echo "word1 word2" | cut -f 1 -d " "
ตัดตัดฟิลด์ที่ 1 (-f 1) ออกจากรายการของฟิลด์ที่คั่นด้วยสตริง "" (-d "")
read
เป็นเพื่อนของคุณ:
หากสตริงอยู่ในตัวแปร:
string="word1 word2"
read -r first _ <<< "$string"
printf '%s\n' "$first"
หากคุณกำลังทำงานในไพพ์: กรณีแรก: คุณต้องการเพียงคำแรกของบรรทัดแรก:
printf '%s\n' "word1 word2" "line2" | { read -r first _; printf '%s\n' "$first"; }
กรณีที่สอง: คุณต้องการคำแรกของแต่ละบรรทัด:
printf '%s\n' "word1 word2" "worda wordb" | while read -r first _; do printf '%s\n' "$first"; done
สิ่งเหล่านี้ใช้ได้หากมีช่องว่างนำหน้า:
printf '%s\n' " word1 word2" | { read -r first _; printf '%s\n' "$first"; }
เนื่องจาก perl รวมฟังก์ชันการทำงานของ awk สิ่งนี้สามารถแก้ไขได้ด้วย perl ด้วย:
echo " word1 word2" | perl -lane 'print $F[0]'
ฉันกำลังทำงานกับอุปกรณ์ฝังตัวที่ไม่มีทั้ง perl, awk หรือ python และทำด้วย sed แทน มันสนับสนุนช่องว่างหลายก่อนที่คำแรก (ที่cut
และbash
การแก้ปัญหาไม่ได้จัดการ)
VARIABLE=" first_word_with_spaces_before_and_after another_word "
echo $VARIABLE | sed 's/ *\([^ ]*\).*/\1/'
สิ่งนี้มีประโยชน์มากเมื่อทำการ grepping ps
สำหรับ ID กระบวนการเนื่องจากโซลูชันอื่น ๆ ที่นี่โดยใช้ bash เพียงอย่างเดียวไม่สามารถลบช่องว่างแรกที่ps
ใช้ในการจัดแนวได้