วิธีรับอักขระสุดท้ายของสตริงในเชลล์


127

ฉันได้เขียนบรรทัดต่อไปนี้เพื่อรับอักขระสุดท้ายของสตริง:

str=$1
i=$((${#str}-1))
echo ${str:$i:1}

ใช้ได้กับabcd/:

$ bash last_ch.sh abcd/
/

มันไม่ทำงานสำหรับabcd* :

$ bash last_ch.sh abcd*
array.sh assign.sh date.sh dict.sh full_path.sh last_ch.sh

มันจะแสดงรายการไฟล์ในโฟลเดอร์ปัจจุบัน

คำตอบ:


99

นั่นเป็นหนึ่งในเหตุผลที่คุณต้องอ้างตัวแปรของคุณ:

echo "${str:$i:1}"

มิฉะนั้น bash จะขยายตัวแปรและในกรณีนี้จะทำการ globbing ก่อนที่จะพิมพ์ออกมา นอกจากนี้ยังเป็นการดีกว่าที่จะอ้างพารามิเตอร์ไปยังสคริปต์ (ในกรณีที่คุณมีชื่อไฟล์ที่ตรงกัน):

sh lash_ch.sh 'abcde*'

ยังเห็นคำสั่งของการขยายในคู่มืออ้างอิงทุบตี ตัวแปรถูกขยายก่อนการขยายชื่อไฟล์

ในการรับอักขระตัวสุดท้ายคุณควรใช้-1เป็นดัชนีเนื่องจากดัชนีเชิงลบนับจากท้ายสตริง:

echo "${str: -1}"

ต้องมีช่องว่างหลังเครื่องหมายทวิภาค ( :)

วิธีนี้จะใช้ไม่ได้หากไม่มีช่องว่าง


62
BTW ดัชนีเชิงลบนับจากทางขวา"${1: -1}"ก็เพียงพอแล้ว
choroba

7
คุณควรตอบกลับเป็นวิธีแก้ปัญหาอย่างเป็นทางการไม่ใช่ที่นี่ในความคิดเห็น
BMW

FYI: คุณสามารถทำใน "ซับเดียว" ได้เช่นecho "${str:$((${#str}-1)):1}"กัน สิ่งนี้ช่วยให้คุณสามารถเปลี่ยนอักขระต่อท้ายที่ส่งคืนได้เช่นกัน งานนี้สำหรับฉันใน bash v4.1.0 (1)
SaxDaddy

16
คำตอบของ @ choroba: สังเกตช่องว่าง! สิ่งนี้ทำให้ฉันรู้สึก"${1:-1}
แย่

192

ต่อ @perreal ตัวแปรการอ้างอิงเป็นสิ่งสำคัญ แต่เนื่องจากฉันอ่านโพสต์นี้เช่น 5 ครั้งก่อนที่จะพบวิธีที่ง่ายกว่าสำหรับคำถามในความคิดเห็น ...

str='abcd/'
echo "${str: -1}"

เอาท์พุท: /

str='abcd*'
echo "${str: -1}"

เอาท์พุท: *

ขอบคุณทุกคนที่เข้าร่วมในสิ่งนี้ข้างต้น ฉันได้เพิ่ม +1 ตลอดทั้งกระทู้อย่างเหมาะสมแล้ว!


25
หมายเหตุ: สังเกตช่องว่างด้านใน${std: -1}โดยไม่มีช่องว่างสิ่งนี้จะไม่ทำงาน ฉันพบสิ่งนี้และพบว่าใช้${std:~0}งานได้เช่นกัน (มีหรือไม่มีที่ว่าง) ไม่แน่ใจว่านี่เป็นพฤติกรรมที่บันทึกไว้หรือไม่ฉันไม่ได้ใส่ใจที่จะค้นหา
บาร์ต

4
มีการบันทึกไว้ man bash พูดว่า: นิพจน์ทางคณิตศาสตร์ที่เริ่มต้นด้วย a - ต้องคั่นด้วยช่องว่างจากก่อนหน้า: เพื่อให้แตกต่างจากการขยาย Use Default Values
mighq

3
เยี่ยมมากขอบคุณสำหรับการแบ่งปัน Manpage BASH แทบจะล้นหลามในการอ่านแม้ว่าฉันเคยไปที่นั่นหลายครั้ง ฉันคิดว่าพวกเขาสามารถสร้างหลักสูตรวิทยาลัยเกี่ยวกับเชลล์สคริปต์ได้ฮ่า ๆ
quickshiftin

3
โซลูชันนี้ใช้ไม่ได้ใน.shสคริปต์เมื่อพยายามกำหนดอักขระที่ดึงข้อมูลให้กับตัวแปร ตัวอย่างเช่นdeclare LAST=$(echo "${str: -1}") สิ่งนี้จะส่งผลให้แถบสีแดงที่น่ารังเกียจแสดงข้อผิดพลาดทางไวยากรณ์โดยเริ่มจาก:
krb686

3
หากการตรวจสอบไวยากรณ์ของตัวแก้ไขไม่ชอบให้ลองเว้นวรรค${str:0-1}
ttt

37

ฉันรู้ว่านี่เป็นกระทู้เก่ามาก แต่ไม่มีใครพูดถึงว่าฉันเป็นคำตอบที่สะอาดที่สุด:

echo -n $str | tail -c 1

โปรดทราบว่า-nเป็นเพียงเพื่อให้เสียงสะท้อนไม่รวมขึ้นบรรทัดใหม่ในตอนท้าย


15
ไม่ถึงกับสะอาดกว่า $ {str: -1}
shrewmouse

8
มันสะอาดกว่าเพราะไม่ต้องพึ่งพา bash-ism ดังนั้นมันจึงใช้ได้กับ Posix shell ใด ๆ
John Eikenberry

"bashist" มากที่สุด? "$ {str: -1}" แล้ว ... อะไรสะอาดที่สุด? "$ {str: -1}" Bash is the besht! :-)
Roger

สำหรับใครก็ตามที่พยายามพิมพ์อักขระสุดท้ายในไฟล์ขนาดใหญ่สิ่งนี้ได้ผลสำหรับฉัน: cat user / folder / file.json | tail -c 1 คุณสามารถแทนที่ 1 ด้วยจำนวนอักขระที่คุณต้องการพิมพ์
Diego Serrano

6

วิธีอื่นโดยใช้สคริปต์ awk:

1 ถ่านสุดท้าย:

echo $str | awk '{print substr($0,length,1)}'

5 ตัวอักษรสุดท้าย:

echo $str | awk '{print substr($0,length-5,5)}'

1
ไม่ใช่สิ่งที่ OP ขอ แต่นี่เป็นทางออกที่ดีที่สุดที่ฉันพบว่าใช้กับไฟล์ วิธีการอื่น ๆ ส่วนใหญ่จะไม่สามารถแก้ไขไฟล์ได้เช่น: cat file | awk '{print substr($0,length,1)}'ขอบคุณ!
xmar

5

ทุกคำตอบมีความหมายถึงคำว่า "เปลือก" ในคำถามเท่ากับ Bash

นี่คือวิธีที่เราสามารถทำได้ใน Bourne เชลล์มาตรฐาน:

printf $str | tail -c 1

2
echo -nตามที่เสนอโดย user5394399 หลีกเลี่ยงปัญหาเมื่อ$strมีอักขระรูปแบบพิเศษ
Conrad Meyer

-nสวิตช์ bashism มันจะไม่ทำงานในเชลล์บอร์นมาตรฐานเป็นเส้นประ ฯลฯ ... ซึ่งเป็นประเด็นของคำตอบของฉัน
phep

1
ไม่ใช่การทุบตี แต่ POSIX รู้ว่ามีการกำหนดการนำไปใช้งาน ("ถ้าตัวถูกดำเนินการตัวแรกเป็น -n หรือหากตัวถูกดำเนินการใด ๆ มีอักขระ <backslash> ผลลัพธ์จะถูกกำหนดให้ใช้งานได้") คำตอบของคุณสามารถแก้ไขได้ด้วยprintf "%s" "$str" | ...:-)
Conrad Meyer

4

แถวเดียว:

${str:${#str}-1:1}

ขณะนี้:

echo "${str:${#str}-1:1}"

1
ทำไมคุณถึงใช้วงเล็บสองคู่? นอกจากนี้ตั้งแต่ 4.2 คุณสามารถใช้การชดเชยเชิงลบดังที่แสดงในคำตอบของ Quickshiftin: echo "${str: -1}"เพียงพอแล้ว (คำนึงถึงช่องว่างระหว่าง:และ-)
gniourf_gniourf

วงเล็บสองคู่ใช้สำหรับการคำนวณทางคณิตศาสตร์
Eduardo Cuomo

ไม่โปรดดูส่วนที่เกี่ยวข้องของคู่มือที่คุณจะอ่าน: ความยาวและออฟเซ็ตคือนิพจน์ทางคณิตศาสตร์ (ดูShell Arithmetic ) ดังนั้นคุณจึงอยู่ในเชลล์เลขคณิตและไม่จำเป็นต้องมีวงเล็บใด ๆ เลย นอกจากนี้ถ้าสิ่งที่คุณกล่าวว่าเป็นความจริงมันจะเป็นตรรกะมากขึ้นที่จะมีการขยายตัวทางคณิตศาสตร์$((...))ด้วย
gniourf_gniourf

@gniourf_gniourf คุณพูดถูก! ตอนนี้ฉันเข้าใจคำถามก่อนหน้าของคุณแล้ว คำตอบอัปเดต
Eduardo Cuomo

4

ลอง:

"${str:$((${#str}-1)):1}"

เช่น:

someone@mypc:~$ str="A random string*"; echo "$str"
A random string*
someone@mypc:~$ echo "${str:$((${#str}-1)):1}"
*
someone@mypc:~$ echo "${str:$((${#str}-2)):1}"
g

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