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?

becko
sumber
1
Duplikat ekstrak-substring-in-bash
Håkon Hægland

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.

Mark Reed
sumber
241

Anda bisa melakukan ini:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"
phe
sumber
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%.*}.

Etan Reisner
sumber
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.

Reut Sharabani
sumber
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}

fredtantini
sumber
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
Avinash Raj
sumber
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

Priya Jain
sumber
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

Siddharth Murugan
sumber
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

Saurabh
sumber
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

Greta
sumber