Bash'teki bir dizeden son n karakteri nasıl kaldırırım?


202

Bir değişken var, bir dizeyi tutan bir Bash komut dosyası var:

echo $var
"some string.rtf"

Bu dizenin son 4 karakterini kaldırmak ve sonucu yeni bir değişkene atamak istiyorum var2, böylece

echo $var2
"some string"

Bunu nasıl yapabilirim?


Yanıtlar:


16

İlk olarak, ne istediğiniz konusunda açık olmalısınız. Dizenin sona erdiğini .rtfve kaldırmak istediğinizi .rtfbiliyorsanız, kullanabilirsiniz var2=${var%.rtf}. Son ekin ne olduğunu bilmiyor ancak sondan başlayarak her şeyi kaldırmak .istiyorsanız, kullanabilirsiniz var2=${var%.*}. Her şeyi sadece birincisine kadar tutmak .istiyorsanız kullanabilirsiniz var2=${var%%.*}. Yalnızca bir nokta varsa, bu son iki seçenek aynı sonucu verir, ancak birden fazla varsa, hangisini istediğinize karar vermelisiniz.

Tam olarak her zaman tam sayıda karakteri kaldırmak istiyorsanız, bazı seçenekler aşağıda verilmiştir.

Özellikle bash'ı belirttiniz, bu yüzden bash yerleşikleriyle başlayalım. En uzun süre çalışan, yukarıda kullandığım son ek kaldırma sözdizimidir: dört karakteri kaldırmak için kullanın var2=${var%????}. Kaldırılan karakter başına bir soru işaretine ihtiyacınız vardır, bu nedenle daha büyük alt dize uzunlukları için kullanılmaz.

Biraz daha yeni çıkarma substring edilir: var2=${var::${#var}-4}. Burada, 4farklı sayıda karakteri kaldırmak için yerine herhangi bir sayı koyabilirsiniz . (Bunun ${#var}yerine dize uzunluğu konur, bu nedenle bu aslında ilk (uzunluk - 4) karakteri korumayı ister.)

Yeni bash sürümleri (özellikle 4+, bu da MacOS ile birlikte gelenin çalışmadığı anlamına gelir) bunu basitleştirmenizi sağlar var2=${var::-4}.

Gerçekten bash kullanmıyorsanız, ancak başka bir POSIX tipi kabuk kullanıyorsanız, sonek kaldırma, düz eski çizgide bile (geri kalanların hiçbirinin olmayacağı) bile çalışmaya devam edecektir. Zsh'de hepsi çalışır, ancak 0iki nokta üst üste arasına bir sütun koymak var2=${var:0:-4}zorundasınız var2=${var:0:${#var}-4}.

Tabii ki bunu bir yardımcı program yardımıyla yapmak için komut yerine kullanabilirsiniz; işe yarayacak çok şey var, ama böyle bir şey var2=$(cut -c -4 <<<"$var")muhtemelen en kısa seçenektir.


245

Bunu şöyle yapabilirsiniz:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"

9
bash 4+ sanırım.
Etan Reisner

69
Öyle bash4+ ama önceki sürümünde size biraz daha uzun kullanabilirsiniz ${v::${#v}-4}.
chepner

8
Benim için çalışmadı, bash `` Kötü ikame '' diyor
Ivan Marjanovic

15
nedense, zsh ${v::-4}croaks "zsh: kapanış ayracı bekleniyor". Ancak @fredtantini'nin aşağıdaki cevabı ${v:0:-4}iyi çalışıyor.
Pierre D

6
Hata: -2: alt dize ifadesi <0
Edward

177

Dizenin sonundan dört karakter çıkarmak için kullanın ${var%????}.

Son .kullanımdan sonra her şeyi çıkarmak için ${var%.*}.


12
Saf kabuk yanıtıdır ve lisans sorunları nedeniyle BASH 4.x'i uygulamayı reddeden birçok sistemde bulunan BASH 3.x'te çalışacaktır.
David W.

1
Daha kısa karakter dizileri elde edilmesine karşı sağlam olduğu için bu iyidir; dizin ofset varyantları başarısız olur.
Raphael

bas

Mükemmel cevap. Dizenin önündeki bir çıkarmaya ne dersiniz?
user2023370

3
@ user2023370 Belgelere başvurmak, bunun için uygun bir parametre ikamesi olduğunu ortaya koymalıdır ${var#????}.
tripleee

48

Benim için işe yarayan şuydu:

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

Ama bir dosyadaki çizgileri kırpmak için kullandım, bu yüzden garip görünüyor. Gerçek kullanım şuydu:

cat somefile | rev | cut -c5- | rev

cutsadece değişken başlangıç ​​sıralarına ihtiyacınız olduğunda kötü olan bir başlangıç ​​konumundan kırpmak kadar ileri götürür. Böylece bu çözüm revdizeyi tersine çevirir ( ) ve şimdi bitiş konumuyla ilişkilidir, daha sonra cutbelirtildiği gibi kullanır ve revorijinal sırasına geri döndürür (tekrar ).


Bu doğru değil ve sorulan soruya bir cevap değil. revdizeleri değil çizgileri tersine çevirir. echo $SOME_VAR | rev | ...muhtemelen birinin nasıl bekleyeceği gibi davranmayacak.
Mohammad Nasirifar

2
Çünkü @Mohammad alıntı kırık olduğunu olan tek bir hat.
tripleee

38

Kullanılması Değişken genişleme / Substring değiştirme :

$ {Var /% Desen / Değiştirme}

Var soneki Desen ile eşleşiyorsa, Desen yerine Yedek kullanın.

Böylece şunları yapabilirsiniz:

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

Alternatif olarak,

Her zaman aynı 4 harfe sahipseniz

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

Her zaman bitiyorsa .xyz:

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

Dizenin uzunluğunu da kullanabilirsiniz:

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

ya da sadece echo ${var::-4}


len=${#var}; echo ${var::len-4}echo ${var:0:-4}:-) DÜZENLEME için kısaltılabilir : ya da @iyonizer'in işaret ettiği gibi, sadece echo ${var::-4}...
anishsane

26

Sed kullanabilirsiniz,

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

Misal:

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

1
ve sonucu nasıl atayabilirim var2?
becko

Bu iyi çünkü böyle bir satırda çalışıyor ... | sed 's /. \ {4 \} $ //'. Değişkenler olmadan kullanılabilir
Sam

4

Aşağıdakileri denedim ve benim için çalıştı:

#! /bin/bash

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

Çıktı: hel


Bu harika. Bu cevabı oldukça uzun zamandır arıyordum. Bu şimdiye kadar python'un yinelenebilir dilimleme işlevselliğine bulduğum en yakın kod.
VanBantam

1

Bu benim için ipin büyüklüğünü hesaplayarak işe yaradı.
İade etmeniz gereken değeri yankılamanız ve daha sonra aşağıdaki gibi depolamanız kolaydır

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

bazı ipler


1

Umarım aşağıdaki örnek yardımcı olacaktır,

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

  • Yukarıdaki komutta isim değişkendir.
  • start dize başlangıç ​​noktasıdır
  • len , kaldırılması gereken dizenin uzunluğudur.

Misal:

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

Çıktı:

    Enter:Siddharth Murugan
    Siddhar

Not: Bash 4.2 negatif alt dize desteği ekledi


Bu, Etan Reisner'ın cevabındaki gibi Bourne uyumlu basit bir desen ikamesinden çok daha ayrıntılıdır.
tripleee

Ayrıca echo "{${name:0:${#name} - 1}}"son karakter kaldırmak ve "alt dize ifadesi <0" hatalarını önlemek için kullanmak zorunda kaldı .
Clemens

0

Bu durumda, kaldırmak istediğiniz dosyalarda aynı soneki olduğunu varsayarak taban adını kullanabilirsiniz.

Misal:

basename -s .rtf "some string.rtf"

Bu, "bazı dizeler" döndürür

Soneki bilmiyorsanız ve son noktadan sonra ve son nokta dahil olmak üzere her şeyi kaldırmasını istiyorsanız:

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

"file" çıktıları

%, pirzola anlamına gelir. doğradığın şey, * joker karakterdir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.