Bagaimana menghapus n karakter terakhir dari string di Bash?


202

Saya memiliki variabel vardalam skrip Bash yang memegang string, seperti:

echo $var
"some string.rtf"

Saya ingin menghapus 4 karakter terakhir dari string ini dan menetapkan hasilnya ke variabel baru var2, jadi

echo $var2
"some string"

Bagaimana saya bisa melakukan ini?


Jawaban:


15

Pertama, Anda harus eksplisit tentang apa yang Anda inginkan. Jika Anda tahu string berakhir .rtfdan Anda ingin menghapusnya .rtf, Anda dapat menggunakannya var2=${var%.rtf}. Jika Anda tidak tahu apa sufiks itu tetapi Anda ingin menghapus semuanya dimulai dengan yang terakhir ., maka Anda bisa menggunakannya var2=${var%.*}. Jika Anda hanya ingin menjaga semuanya tetap up to the first ., Anda bisa menggunakannya var2=${var%%.*}. Dua opsi terakhir memiliki hasil yang sama jika hanya ada satu periode, tetapi jika mungkin ada lebih dari satu periode, Anda harus memutuskan mana yang Anda inginkan.

Jika Anda benar-benar ingin selalu menghapus jumlah karakter yang tepat, berikut adalah beberapa opsi.

Anda menentukan bash secara spesifik, jadi kami akan mulai dengan bash builtin. Salah satu yang telah bekerja paling lama adalah sintaks suffix-removal yang sama yang saya gunakan di atas: untuk menghapus empat karakter, gunakan var2=${var%????}. Anda perlu satu tanda tanya per karakter dihapus, jadi ini menjadi sulit untuk panjang substring yang lebih besar.

Sedikit lebih baru adalah substring ekstraksi: var2=${var::${#var}-4}. Di sini Anda dapat meletakkan nomor apa saja 4untuk menghapus sejumlah karakter yang berbeda. ( ${#var}Digantikan oleh panjang string, jadi ini sebenarnya meminta untuk menjaga karakter pertama (panjang - 4).)

Versi bash yang lebih baru (khususnya 4+, yang berarti yang dikirimkan dengan MacOS tidak berfungsi) memungkinkan Anda menyederhanakannya menjadi adil var2=${var::-4}.

Jika Anda tidak benar-benar menggunakan bash tetapi beberapa shell tipe POSIX lainnya, penghapusan suffix akan tetap bekerja, bahkan di dasbor lama biasa (di mana tidak ada yang akan melakukannya). Dalam zsh, mereka semua bekerja tetapi Anda harus menempatkan 0antara titik dua: var2=${var:0:-4}dll di ksh, Anda memerlukan 0 dan juga harus menggunakan eksplisit panjang-4 ekspresi: var2=${var:0:${#var}-4}.

Anda tentu saja dapat menggunakan substitusi perintah untuk melakukannya dengan bantuan program utilitas; ada banyak yang akan berhasil, tetapi sesuatu seperti var2=$(cut -c -4 <<<"$var")mungkin merupakan pilihan terpendek.


241

Anda bisa melakukan ini:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"

9
bash 4+ saya pikir.
Etan Reisner

69
Ini bash4+, tetapi dalam versi sebelumnya Anda dapat menggunakan sedikit lebih lama ${v::${#v}-4}.
chepner

8
Tidak bekerja untuk saya, kata bash '' Substitusi buruk '
Ivan Marjanovic

15
untuk beberapa alasan, di zsh ${v::-4}croaks "zsh: closure brace diharapkan". Tapi jawaban @fredtantini di bawah ini ${v:0:-4}berfungsi dengan baik.
Pierre D

6
Kesalahan dengan: -2: ekspresi substring <0
Edward

173

Untuk menghapus empat karakter dari akhir penggunaan string ${var%????}.

Untuk menghapus semuanya setelah akhir .digunakan ${var%.*}.


12
Pure shell menjawab, dan akan bekerja di BASH 3.x yang ditemukan di banyak sistem yang menolak menerapkan BASH 4.x karena masalah lisensi.
David W.

1
Ini keren karena kuat melawan string yang lebih pendek; varian indeks offset gagal.
Raphael

bekerja di bash 3.2.25 - jawaban terbaik yang mungkin - hanya apa yang saya cari
capser

Jawaban yang sangat bagus. Bagaimana dengan penghapusan di bagian depan string?
user2023370

3
@ user2023370 Berkonsultasi dokumentasi harus mengungkapkan bahwa ada substitusi parameter yang sesuai ${var#????}untuk itu.
tripleee

48

Apa yang berhasil untuk saya adalah:

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

Tapi saya menggunakannya untuk memangkas baris dalam file sehingga itu terlihat canggung. Penggunaan sebenarnya adalah:

cat somefile | rev | cut -c5- | rev

cuthanya membuat Anda sejauh pemangkasan dari beberapa posisi awal, yang buruk jika Anda membutuhkan baris panjang variabel. Jadi solusi ini membalikkan ( rev) string dan sekarang kita berhubungan dengan posisi akhirnya, kemudian menggunakan cutseperti yang disebutkan, dan membalikkan (lagi, rev) kembali ke urutan aslinya.


Ini tidak benar dan bukan jawaban atas apa yang ditanyakan. revmembalikkan garis, bukan string. echo $SOME_VAR | rev | ...mungkin tidak akan berperilaku seperti yang diharapkan.
Mohammad Nasirifar

2
@Mohammad Karena kutipan yang rusak, itu adalah satu baris.
tripleee

38

Menggunakan Variabel ekspansi / penggantian Substring :

$ {var /% Pola / Penggantian}

Jika sufiks var cocok dengan Pattern, maka gantilah Replacement for Pattern.

Jadi kamu bisa melakukan:

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

Kalau tidak,

Jika Anda selalu memiliki 4 huruf yang sama

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

Jika selalu berakhir dengan .xyz:

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

Anda juga dapat menggunakan panjang string:

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

atau sederhana echo ${var::-4}


len=${#var}; echo ${var::len-4}dapat disingkat menjadi echo ${var:0:-4}:-) EDIT: atau seperti yang ditunjukkan @iyonizer, hanya echo ${var::-4}...
anishsane

26

Anda bisa menggunakan sed,

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

Contoh:

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

1
dan bagaimana cara menetapkan hasilnya var2?
becko

ini bagus karena berfungsi pada satu baris seperti ini ... | sed 's /. \ {4 \} $ //'. Dapat digunakan tanpa menggunakan variabel
Sam

3

Saya mencoba yang berikut ini dan berhasil untuk saya:

#! /bin/bash

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

Keluaran: hel


1

Semoga contoh di bawah ini akan membantu,

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

  • Dalam perintah di atas, nama adalah variabel.
  • start adalah titik awal string
  • len adalah panjang string yang harus dihapus.

Contoh:

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

Keluaran:

    Enter:Siddharth Murugan
    Siddhar

Catatan: Bash 4.2 menambahkan dukungan untuk substring negatif


Ini jauh lebih verbose daripada substitusi pola sederhana Bourne-kompatibel seperti dalam jawaban Etan Reisner.
tripleee

0

Ini bekerja untuk saya dengan menghitung ukuran string.
Sangat mudah Anda perlu mengulangi nilai yang Anda butuhkan untuk kembali dan kemudian menyimpannya seperti di bawah ini

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

beberapa string


0

Dalam hal ini Anda bisa menggunakan nama samaran dengan asumsi Anda memiliki akhiran yang sama pada file yang ingin Anda hapus.

Contoh:

basename -s .rtf "some string.rtf"

Ini akan mengembalikan "beberapa string"

Jika Anda tidak tahu sufiks, dan ingin menghapus semuanya setelah dan termasuk titik terakhir:

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

output "file"

% berarti memotong,. adalah apa yang Anda memotong, * adalah wildcard

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.