วิธียืนยันว่าสตริงมีอักขระขึ้นบรรทัดใหม่และหากเป็นเช่นนั้นให้ลบออก


9

ฉันมีสตริงที่เป็นผลมาจากการดำเนินการบางอย่างที่ฉันไม่สามารถควบคุมได้ เมื่อฉันพิมพ์ตัวแปรนี้โดยใช้echoฉันได้รับ:

echo $myvar
hello

อย่างไรก็ตามเมื่อฉันทำ

if [ $myvar = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

ฉันได้เสมอว่าพวกเขาไม่เท่ากัน ฉันสงสัยว่านี่เป็นเพราะnewlineตัวละคร

สตริงยังมีพฤติกรรมที่แปลกด้วย เมื่อฉันทำ:

newVAR="this is my var twice: "$myvar$myvar
echo $newVAR

ฉันเข้าใจ:

hellois my var twice: hello

ฉันจะตรวจสอบได้อย่างไรว่านี่เป็นเรื่องจริงเนื่องจาก a newlineและถ้าใช่ให้ลบออก


1
ใน Bash คุณสามารถprintf '%q\n' "$string"รับสายอักขระรุ่นใดก็ได้ ตัวอย่างเช่น: printf '%q\n' 'foo\n'-> foo\\n; printf '%q\n' $'foo\n'->$'foo\n'
l0b0

1
คุณไม่ได้อ้างถึงการขยายตัวของตัวแปรใด ๆ ของคุณ หากพวกเขาไม่ได้มีช่องว่างต่อท้ายใด ๆ echo $fooที่คุณจะไม่เห็นด้วย ทำecho "$foo"แทน
Peter Cordes

คำตอบ:


9

ปัญหาคือคุณมี Carriage-Return (CR, \r) ในตัว สิ่งนี้ทำให้จุดแทรกข้อความเทอร์มินัลเตะกลับไปที่จุดเริ่มต้นของบรรทัดที่กำลังพิมพ์ นั่นคือเหตุผลที่คุณเห็น 'สวัสดี' ที่จุดเริ่มต้นของบรรทัดใน$newVARตัวอย่าง - sed -n lแสดงมุมมองที่อ่านได้ของอักขระที่ไม่สามารถพิมพ์ได้ (และท้ายบรรทัด)

var=ab$'\r'c ; echo "$var";  printf %s "$var" | sed -n l
# output:
cb
ab\rc$

คุณสามารถทดสอบได้ด้วยการตรวจสอบเงื่อนไขการทุบตีอย่างง่าย:

[[ $var == *$'\r'* ]] && echo yes || echo no
# output:
yes

คุณสามารถรวมการทดสอบและแก้ไขในขั้นตอนเดียวโดยการทดสอบ\rและลบออกผ่าน:

fix="${var//$'\r'/}"; echo "$var"; echo "$fix"
# output:
cb
abc

แก้ไขใช้ขยายเชลล์พารามิเตอร์ รูปแบบเฉพาะที่ใช้ด้านบนนี้ใช้สำหรับการแทนที่วัสดุพิมพ์ตามรูปแบบที่ได้รับการออกแบบของคุณ: ${parameter/pattern/string}<- ซึ่งจะแทนที่รูปแบบที่พบครั้งแรกเท่านั้นที่มีสตริงในพารามิเตอร์ชื่อตัวแปร * เพื่อแทนที่ทุกรูปแบบคุณก็ต้องเปลี่ยนคนแรกที่ไป///


คุณช่วยอธิบายรหัสสุดท้ายหน่อยได้ไหม? fix="....สาย?
Farid99

@ farid99: คำอธิบายที่เพิ่มเข้ามาเพื่อตอบหมายเหตุfixสามารถเป็นvarตัวของตัวเอง - หรือบ่อยครั้งที่คุณสามารถใช้การขยายพารามิเตอร์ตามที่เป็นอยู่โดยไม่จำเป็นต้องกำหนดค่าที่แก้ไข (อาจ) กำหนดใหม่ ..
Peter.O

5

คุณสามารถแสดง\rเป็น$'\r'ในทุบตี:

if [ "$myvar" = "hello"$'\r' ]; then
    echo they are equal
else
    echo they are not equal
fi

หรือสับคนสุดท้าย\rในmyvar:

if [ "${myvar%$'\r'*}" = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

3

อยากรู้อยากเห็นในเปลือกหอยจำนวนมากgetoptsเป็นผู้สมัครที่มีโอกาสมากสำหรับงานแบบนี้ นี่อาจดูเหมือน counterintuitive ในตอนแรก แต่ถ้าคุณพิจารณาว่าgetopts'ฟังก์ชั่นหลักคือการรับรู้และเสนอขึ้นสำหรับการตีความเป็นตัวเลือกบรรทัดคำสั่งอักขระตัวเดียวหลายตัวที่ระบุไว้ซึ่งอาจพบได้ในซีรีส์ที่ต่อกันกัน ความรู้สึกมากขึ้น

เพื่อสาธิตจากbashเชลล์:

x=$(printf '\n\r%010s\t' hello)
OPTIND=1
while  getopts : na "-$x"
do     printf %q\\n "$OPTARG"
done

$'\n'
$'\r'
\
\
\
\
\
h
e
l
l
o
$'\t'

ด้วยวิธีนี้ในบางครั้งการอนุญาตให้getoptsจัดการถอดแยกชิ้นส่วนเป็นเปลือกนักบินอัตโนมัติสำหรับกรณีเช่นนี้ เมื่อคุณทำเช่นนั้นคุณสามารถคัดกรองไบต์ที่ไม่ต้องการด้วยการทดสอบcaseหรือสร้างสตริงการสำรองข้อมูลจากไบต์ 1:[]

OPTIND=1 y=$(printf \\n\\r) z=
while  getopts : na "-$x"
do     case $OPTARG in ([!$y])
            z=$z$OPTARG
       esac
done
printf %q\\n "$z"

$'     hello\t'

ระบุกรณีตัวอย่างอย่างง่ายนี้ - และกำหนดเชลล์ที่สนับสนุนการขยายพารามิเตอร์ที่กล่าวถึงแล้วในที่อื่น - กล่าวว่าการขยายอาจจะให้บริการคุณได้ดีขึ้นที่นี่ แต่ฉันคิดว่าgetoptsอาจจะคุ้มค่ากับการพูดถึงเช่นกันในกรณีที่คุณไม่ได้ตระหนักถึงความสามารถของมันในแง่นี้ แน่นอนเมื่อฉันเรียนรู้มันฉันพบแอปพลิเคชั่นที่มีประโยชน์มากมาย


0

ในขณะที่ Bash และภาษาอื่น ๆ ของเชลล์มีประโยชน์บางครั้งก็เป็นการดีกว่าถ้าใช้ภาษาสคริปต์ที่แท้จริง - เช่น Perl Perl สามารถแทนที่เชลล์สคริปต์ที่เรียกใช้ภาษาอื่นเช่น sed และ awk รวมถึงคำสั่ง UNIX ได้อย่างง่ายดาย ฉันได้เรียนรู้สิ่งนี้เมื่อ 20 ปีก่อนเมื่อเขียนสคริปต์ C-Shell ซึ่งเรียกว่าคำสั่ง sed, awk และ UNIX ต่าง ๆ - ก่อนที่จะเรียกรหัส FORTRAN ใน Perl ฉันจะทำ:

chomp($myvar);   # removes the newline char

if("$myvar" eq "hello")   # string comparison
  {
  print "they are equal\n";
  }
else
  {
  print "they are not equal\n";
  }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.