bash: การกำหนดบรรทัดแรกของตัวแปรให้กับตัวแปร


11

ฉันมีตัวแปรหลายบรรทัดและฉันต้องการเพียงบรรทัดแรกในตัวแปรนั้น สคริปต์ต่อไปนี้แสดงให้เห็นถึงปัญหา:

#!/bin/bash

STRINGTEST="Onlygetthefirstline
butnotthesecond
orthethird"

echo "  Take the first line and send to standard output:"
echo ${STRINGTEST%%$'\n'*}
#   Output is as follows:
# Onlygetthefirstline

echo "  Set the value of the variable to the first line of the variable:"
STRINGTEST=${STRINGTEST%%$'\n'*}

echo "  Send the modified variable to standard output:"
echo $STRINGTEST
#   Output is as follows:
# Onlygetthefirstline butnotthesecond orthethird

คำถาม: ทำไม${STRINGTEST%%$'\n'*}ส่งคืนบรรทัดแรกเมื่อวางหลังจากechoคำสั่ง แต่แทนที่บรรทัดใหม่ด้วยช่องว่างเมื่อวางหลังจากการกำหนด?


1
ไม่สามารถทำซ้ำได้ มันทำงานได้สำหรับฉันตามที่คาดไว้
Peque

1
ไม่สามารถทำซ้ำกับ 2.05b, 3.1, 3.2, 4.0, 4.1, 4.2, 4.3 อย่างใดอย่างหนึ่ง ดูเหมือนว่าข้อผิดพลาดของผู้ใช้เช่นพยายามเรียกใช้ด้วยเชลล์ที่ไม่สนับสนุน$'...'แทนที่จะทุบตี
Stéphane Chazelas

คำตอบ:


8

อาจมีวิธีอื่นในการเก็บถาวรสิ่งที่คุณต้องการ แต่วิธีนี้ใช้ได้ผล

#!/bin/bash

STRINGTEST="
Onlygetthefirstline
butnotthesecond
orthethird
"

STRINGTEST=(${STRINGTEST[@]})
echo "${STRINGTEST[0]}"

ซึ่งถือว่าบรรทัดใน$STRINGTESTไม่มีช่องว่างหรือสัญลักษณ์แทน นอกจากนี้โปรดทราบว่าระบบจะละเว้นบรรทัดว่างเปล่า (ดังเช่นในบรรทัดแรกในตัวแปรนั้น)
Stéphane Chazelas

3
นอกจากนี้ยังทราบว่าการใช้STRINGTEST=(${STRINGTEST[@]})จะทำให้ความรู้สึกเล็ก ๆ น้อย ๆ และเทียบเท่ากับSTRINGTEST=($STRINGTEST)ตั้งแต่STRINGTESTถูกกำหนดไว้ก่อนหน้าเป็นสเกลาร์ (ไม่อาร์เรย์ตัวแปร)
Stéphane Chazelas

10

อาจไม่ได้มีประสิทธิภาพมากที่สุด แต่ซับเดียว ...

firstLine=`echo "${multiLineVariable}" | head -1`

2
ฉันชอบมันเพื่อความชัดเจนและความกะทัดรัด
Peter - Reinstate Monica

วิธีfirstLine=`echo "${test_var}" | sed -n 1pนี้ใช้งานได้หากคุณมีเหตุผลที่จะใช้ sed แทน (เช่นหมายความว่าคุณสามารถดำเนินการแทนบรรทัดได้พร้อมกัน: echo "${test_var}" | sed -nE '1 s/# *(.*)/\1/p'.
robenkleene

7

รหัสนั้นใช้ได้สำหรับฉันกับ bash ทุกรุ่นที่ฉันลองระหว่าง 2.05b และ 4.3 มีโอกาสมากขึ้นที่คุณพยายามเรียกใช้สคริปต์ด้วยเชลล์ที่แตกต่างกันซึ่งไม่สนับสนุน$'...'รูปแบบการอ้างอิง

นั่น$'...'ไวยากรณ์ไม่ได้มาตรฐานshไวยากรณ์ (ยัง) และการสนับสนุนเฉพาะ ( ณ วันที่ 2015/05/22 และ AFAIK) โดยksh93(ที่มันเกิดขึ้น) zsh, bashรุ่นล่าสุดmkshและshหรือล่าสุดรุ่นของ FreeBSD

เดิมพันของฉันจะเป็นได้ว่าคุณพยายามที่จะเรียกใช้สคริปต์ที่มีshแทนbashและคุณshจะขึ้นอยู่กับรุ่นของash, pdksh, yashหรือksh88ที่ไม่สนับสนุนมันยัง

หากคุณต้องการให้โค้ด POSIX 2008 นั้นใช้งานร่วมกันได้คุณต้องเขียนมัน:

STRINGTEST="Onlygetthefirstline
butnotthesecond
orthethird"

NL='
'
STRINGTEST=${STRINGTEST%%"$NL"*}
printf '%s\n' "$STRINGTEST"

จากนั้นคุณสามารถตีความมันได้โดยเชลล์ที่สอดคล้องกับ POSIX bashใด ๆ หรือshไลเนอร์ที่เร็วกว่าเช่นคุณ

(และจำไว้ว่าการคงไว้ซึ่งตัวแปรที่ไม่ได้ระบุไว้ในบริบทรายการมีความหมายพิเศษมากในเชลล์คล้ายบอร์น)


หรืออาจเป็นทุบตีรุ่นเก่ากว่า ฉันสามารถทำซ้ำพฤติกรรมด้วย 2.03
Gilles 'หยุดความชั่วร้าย' Gilles

@Gilles ระบบปฏิบัติการล่าสุดที่รองรับซึ่งรวมถึง bash-2.03 (เปิดตัวเมื่อ 16 ปีที่แล้ว) น่าจะเป็น Solaris 8 ซึ่งใช้งาน EOL ในช่วง 3 ปีที่ผ่านมา สมมติฐานนั้นดูเหมือนไม่น่าจะเป็นไปได้
Stéphane Chazelas

1

สิ่งนี้ใช้ได้กับฉัน:

STRINGTEST="Some Text 1
Some Text 2
Some Text 3"

readarray -t lines < <(echo "$STRINGTEST")
echo "${lines[0]}"

และยังใช้งานได้กับบรรทัดว่าง:

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"

readarray -t lines < <(echo "$STRINGTEST")
echo "${lines[0]}"

หากมีใครมารบกวนการทดแทนกระบวนการก็สามารถทำได้เพียงแค่readครั้งเดียวในตัวแปรง่าย ๆ (แทนที่จะเป็นreadarrayดัชนีบวก)
ปีเตอร์ - Reinstate Monica

0

ด้วย Bash ในตัวreadและที่นี่สตริง:

#!/usr/bin/env bash

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"


IFS=$'\n' read -r STRINGTEST <<<"$STRINGTEST"

การใช้การขยายพารามิเตอร์ POSIX:

#!/usr/bin/env sh

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"

# Disables globing
set -f

# Field separator is newline only
IFS="
"

# No quotes, split lines as arguments because of IFS
set -- $STRINGTEST

# First argument is first line
STRINGTEST="$1"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.