วิธีการลบอักขระสุดท้าย n ออกจากสตริงใน Bash


202

ฉันมีตัวแปรvarในสคริปต์ Bash ถือสตริงเช่น:

echo $var
"some string.rtf"

ฉันต้องการลบอักขระ 4 ตัวสุดท้ายของสตริงนี้และกำหนดผลลัพธ์ให้กับตัวแปรใหม่var2ดังนั้น

echo $var2
"some string"

ฉันจะทำสิ่งนี้ได้อย่างไร


1
สำเนาของการแยก
ซับ

คำตอบ:


15

ก่อนอื่นคุณควรมีความชัดเจนเกี่ยวกับสิ่งที่คุณต้องการ ถ้าคุณรู้ว่าปลายสตริงใน.rtfและคุณต้องการที่จะลบคุณสามารถใช้.rtf var2=${var%.rtf}หากคุณไม่ได้รู้ว่าสิ่งที่ต่อท้ายเป็น แต่คุณต้องการที่จะลบทุกอย่างเริ่มต้นด้วยสุดท้ายแล้วคุณสามารถใช้. var2=${var%.*}ถ้าคุณเพียงต้องการที่จะให้ทุกอย่างขึ้นกับครั้งแรกที่คุณสามารถใช้. var2=${var%%.*}ตัวเลือกสองตัวสุดท้ายเหล่านั้นมีผลลัพธ์เหมือนกันหากมีเพียงช่วงเวลาเดียว แต่หากอาจมีมากกว่าหนึ่งตัวคุณควรตัดสินใจเลือกสิ่งที่คุณต้องการ

หากคุณต้องการลบจำนวนอักขระที่แน่นอนเสมอนี่คือตัวเลือกบางตัว

คุณระบุ bash เป็นพิเศษดังนั้นเราจะเริ่มด้วย bash builtins var2=${var%????}หนึ่งซึ่งมีการทำงานที่ยาวที่สุดคือไวยากรณ์ต่อท้ายกำจัดเดียวกันผมใช้ข้างต้นที่จะเอาสี่ตัวอักษรใช้ คุณต้องลบเครื่องหมายคำถามหนึ่งตัวต่อหนึ่งตัวอักษรดังนั้นสิ่งนี้จะยากขึ้นสำหรับความยาวสตริงย่อยที่ใหญ่

เล็กน้อยที่ใหม่กว่า substring var2=${var::${#var}-4}สกัด: ที่นี่คุณสามารถใส่หมายเลขใดก็ได้4เพื่อลบจำนวนอักขระที่แตกต่างกัน (ตัว${#var}ถูกแทนที่ด้วยความยาวของสตริงดังนั้นจึงขอให้เก็บอักขระ (ความยาว - 4) ตัวแรก)

รุ่นใหม่ของทุบตี (เฉพาะ 4+ ซึ่งหมายความว่าคนที่มาพร้อมกับ MacOS จะไม่ทำงาน) var2=${var::-4}ช่วยให้คุณลดความซับซ้อนที่จะเพียงแค่

หากคุณไม่ได้ใช้ทุบตีจริง ๆ แต่เชลล์ชนิด POSIX อื่น ๆ การลบคำต่อท้ายจะยังคงใช้ได้แม้อยู่ในเส้นประเก่าแบบธรรมดา ใน zsh พวกเขาทุกงาน แต่คุณต้องใส่0ระหว่างทวิภาคนี้var2=${var:0:-4}ฯลฯ ใน ksh คุณต้อง 0 และยังมีการใช้อย่างชัดเจนความยาว 4 var2=${var:0:${#var}-4}แสดงออก:

แน่นอนคุณสามารถใช้การทดแทนคำสั่งเพื่อทำมันด้วยความช่วยเหลือของโปรแกรมอรรถประโยชน์; มีมากมายที่จะทำงานได้ แต่สิ่งที่ชอบvar2=$(cut -c -4 <<<"$var")น่าจะเป็นตัวเลือกที่สั้นที่สุด


240

คุณสามารถทำสิ่งนี้:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"

9
ทุบตี 4+ ฉันคิดว่า
Etan Reisner

69
มันเป็นbash4+ ${v::${#v}-4}แต่ในรุ่นก่อนหน้านี้คุณสามารถใช้อีกเล็กน้อย
chepner

8
ไม่ได้ผลสำหรับฉัน bash กล่าวว่า '' การแทนที่ไม่ถูกต้อง '
Ivan Marjanovic ใน

15
ด้วยเหตุผลบางอย่างใน zsh ${v::-4}croaks "zsh: คาดว่าจะปิดวงเล็บ" แต่คำตอบของ @fredtantini ด้านล่าง${v:0:-4}ใช้ได้ดี
Pierre D

6
ข้อผิดพลาดกับ: -2: นิพจน์สตริงย่อย <0
Edward

173

${var%????}ในการลบอักขระสี่ตัวจากจุดสิ้นสุดของการใช้สตริง

ในการลบทุกอย่างหลังจากสุดท้ายการใช้งาน.${var%.*}


12
คำตอบของเชลล์บริสุทธิ์และจะทำงานใน BASH 3.x ที่พบในหลาย ๆ ระบบที่ปฏิเสธที่จะใช้ BASH 4.x เนื่องจากปัญหาด้านลิขสิทธิ์
David W.

1
นี่มันเจ๋งมากเพราะมันแข็งแกร่งเมื่อเทียบกับการรับสายสั้น ๆ ตัวแปรออฟเซ็ตดัชนีจะล้มเหลว
กราฟิลส์

ทำงานใน bash 3.2.25 - คำตอบที่ดีที่สุด - สิ่งที่ฉันกำลังมองหา
capser

คำตอบที่ยอดเยี่ยม วิธีการเกี่ยวกับการลบที่ด้านหน้าของสตริงหรือไม่
user2023370

3
@ user2023370 ให้คำปรึกษาเอกสารควรเปิดเผยว่ามีการเปลี่ยนตัวพารามิเตอร์ที่สอดคล้องกัน${var#????}ว่า
tripleee

48

สิ่งที่ทำงานให้ฉันคือ:

echo "hello world" | rev | cut -c5- | rev
# hello w

แต่ฉันใช้มันเพื่อตัดเส้นในไฟล์ดังนั้นนั่นจึงเป็นเหตุผลที่ทำให้ดูเคอะเขิน การใช้งานจริงคือ:

cat somefile | rev | cut -c5- | rev

cutเพียงทำให้คุณได้รับการตัดแต่งจากตำแหน่งเริ่มต้นซึ่งไม่ดีหากคุณต้องการแถวความยาวผันแปร ดังนั้นวิธีนี้จึงย้อนกลับ ( rev) สตริงและตอนนี้เราเกี่ยวข้องกับตำแหน่งสิ้นสุดของมันจากนั้นใช้cutตามที่กล่าวไว้และย้อนกลับ (อีกครั้งrev) กลับไปเป็นคำสั่งเดิม


สิ่งนี้ไม่ถูกต้องและไม่ใช่คำตอบสำหรับสิ่งที่ถูกถาม revฝืนเส้นไม่ใช่สาย echo $SOME_VAR | rev | ...อาจจะไม่ทำงานตามที่คาดไว้
Mohammad Nasirifar

2
@ โมฮัมหมัดเนื่องจากการอ้างที่ขาดนั่นเป็นบรรทัดเดียว
tripleee

38

ใช้ตัวแปรการขยาย / Substring แทน :

$ {var / รูปแบบ% / เปลี่ยน}

หากส่วนต่อท้ายของ var ตรงกับรูปแบบให้เปลี่ยนทดแทนสำหรับรูปแบบ

ดังนั้นคุณสามารถทำได้:

~$ echo ${var/%????/}
some string

อีกวิธีหนึ่งคือ

หากคุณมีตัวอักษร 4 ตัวเสมอ

~$ echo ${var/.rtf/}
some string

หากมันสิ้นสุดใน.xyz:

~$ echo ${var%.*}
some string

คุณยังสามารถใช้ความยาวของสตริง:

~$ len=${#var}
~$ echo ${var::len-4}
some string

หรือเพียงแค่ echo ${var::-4}


len=${#var}; echo ${var::len-4}อาจจะลงไปecho ${var:0:-4}:-) แก้ไข: หรือเป็น @iyonizer ชี้ให้เห็นเพียงแค่echo ${var::-4}...
anishsane

26

คุณสามารถใช้ sed

sed 's/.\{4\}$//' <<< "$var"

ตัวอย่าง:

$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string

1
และฉันจะกำหนดผลลัพธ์ให้ได้var2อย่างไร
becko

นี่เป็นสิ่งที่ดีเพราะมันใช้งานได้ในหนึ่งบรรทัดเช่นนี้ ... | sed 's /. \ {4 \} $ //' สามารถใช้งานได้โดยไม่ต้องใช้ตัวแปร
Sam

3

ฉันลองสิ่งต่อไปนี้และได้ผลกับฉัน:

#! /bin/bash

var="hello.c"
length=${#var}
endindex=$(expr $length - 4)
echo ${var:0:$endindex}

เอาท์พุท: hel


1

หวังว่าตัวอย่างด้านล่างจะช่วยได้

echo ${name:0:$((${#name}-10))} -> ${name:start:len}

  • ในคำสั่งด้านบนชื่อเป็นตัวแปร
  • start เป็นจุดเริ่มต้นของสตริง
  • len คือความยาวของสตริงที่ต้องถูกลบออก

ตัวอย่าง:

    read -p "Enter:" name
    echo ${name:0:$((${#name}-10))}

เอาท์พุท:

    Enter:Siddharth Murugan
    Siddhar

หมายเหตุ: Bash 4.2 เพิ่มการสนับสนุนสำหรับสตริงย่อยเชิงลบ


นี่คือ verbose มากกว่าการแทนที่รูปแบบง่าย ๆ ที่เข้ากันได้กับบอร์นเหมือนกับคำตอบของ Etan Reisner
tripleee

0

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

removechars(){
        var="some string.rtf"
        size=${#var}
        echo ${var:0:size-4}  
    }
    removechars
    var2=$?

สตริงบางส่วน


0

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

ตัวอย่าง:

basename -s .rtf "some string.rtf"

นี่จะส่งคืน "สตริงบางส่วน"

หากคุณไม่ทราบคำต่อท้ายและต้องการให้ลบทุกอย่างหลังจากนั้นและรวมถึงจุดสุดท้าย:

f=file.whateverthisis
basename "${f%.*}"

ส่งออก "ไฟล์"

หมายถึงการสับ คือสิ่งที่คุณกำลังจะสับ * เป็นสัญลักษณ์แทน

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