Kabuk komut dosyasında string manipülasyonunu kullanarak dizgenin son karakterini silin


187

Bir dizgenin son karakterini silmek istiyorum, bu küçük betiği denedim:

#! /bin/sh 

t="lkj"
t=${t:-2}
echo $t

ama "lkj" yazıyor, yanlış ne yapıyorum?

Yanıtlar:


115

Bir POSIX kabuğunda, sözdizimi ${t:-2}farklı bir şey ifade eder - teğer tayarlanmış ve boş olmamışsa, aksi halde değere doğru genişler 2. Tek bir karakteri parametre genişletme ile kesmek için, muhtemelen istediğiniz sözdizimi${t%?}

Ki Not ksh93, bashya zsh, ${t:(-2)}veya ${t: -2}(boşluk dikkat edin) olan bir alt dize genişleme gibi yasal ama onlar (ucundan bir pozisyonda 2 karakter başlayan alt dize döndürür beri, ne istediğini muhtemelen değil yani o kaldırır ilk karakteri iarasında dize ijk).

Daha fazla bilgi için Bash Referans Kılavuzunun Shell Parametre Genişletme bölümüne bakın:


4
'%' Nin ardındaki sihrin ne olduğunu açıklamak ister misiniz? ?
afraisse

8
@ afraisse ${parameter%word}en kısa son ek desen eşleştirmesini kaldırır word- bkz. Parametre Genişletme bölümüman bash
steeldriver

3
Bu, Bash 4.1.2 için iyi çalışıyor: CentOS / RHEL 6.x ile sıkışan insanlar için {$ t $?} $ 6.6
Joey T

185

İle bashyukarıda 4.2 ve yapabileceğiniz:

${var::-1}

Örnek:

$ a=123
$ echo "${a::-1}"
12

Daha eskiler için bash(örneğin, bash 3.2.5OS X'te), kolonların arasında ve sonrasında boşluk bırakmanız gerektiğine dikkat edin:

${var: : -1}

13
Bu bashsürüm 4.2-alfa ve üzeri sürümlerde çalışır , erişebileceğim sürümün önceki sürümleri çok kötü. : - /
hjk

2
@iamaziz: Bash changelog'dan negatif uzunluk ${var:offset:lenght}yalnızca içeriye eklendi bash 4.2. Belki OSX kendi yamasını ekler bash.
cuonglm

1
@cuonglm ne işe yaramazsa: /
iamaziz

1
Mac üzerinde çalışmıyor.
shinzou

1
MACsters, Russ'ın cevabına dikkat edin
P i

67

son nkarakterleri, kullanılmayan bir satırdan kaldırmak içinsedVEYAawk :

> echo lkj | rev | cut -c (n+1)- | rev

yani son karakteri silebilirsiniz one character kullanarak :

> echo lkj | rev | cut -c 2- | rev

> lk

dan revman:

AÇIKLAMA
rev programı belirtilen dosyaları standart çıktıya kopyalar ve her satırdaki karakter sırasını tersine çevirir. Herhangi bir dosya belirtilmemişse, standart giriş okunur.

GÜNCELLEME:

dizenin uzunluğunu bilmiyorsanız, şunu deneyin:

$ x="lkj"
$ echo "${x%?}"
lk

62

Sed kullanarak bu kadar hızlı olmalı

sed 's/.$//'

Sizin tek yankı o zaman echo ljk | sed 's/.$//'.
Bunu kullanarak, 1 satır dize herhangi bir boyutta olabilir.


10
Genel durumda, unutmayın dizenin son karakteri silmek , ancak son karakteri dizenin her satırının .
Stéphane Chazelas

44

Kabuğa bağlı olarak birkaç seçenek:

  • POSIX: t=${t%?}
  • Bourne: t=`expr " $t" : ' \(.*\).'`
  • zsh / yash: t=${t[1,-2]}
  • bash / zsh: t=${t:0:-1}
  • ksh93 / bash / zsh / mksh: t=${t:0:${#t}-1}
  • ksh93 / bash / zsh / mksh: t=${t/%?}
  • ksh93: t=${t/~(E).$/}
  • es: @ {t=$1} ~~ $t *?

Hepsinin son karakteri çıkarması gerektiğine dikkat edin, bazı uygulamaların (çoklu bayt karakterleri desteklemeyenlerin) bunun yerine son baytı soyduğunu görürsünüz ( eğer çoklu bayt olsaydı son karakteri bozabilir) ).

exprVaryantı varsayar $tbirden fazla satır karakteriyle bitmiyor. Ayrıca, sonuçta ortaya çıkan dizge bitmişse 0( 000veya hatta -0bazı uygulamalarda) sıfır olmayan bir çıkış durumu döndürür . Dize geçersiz karakterler içeriyorsa, beklenmeyen sonuçlar verebilir.


Güzel ve kapsamlı! Ama ... tüm bu mermilerin POSIX'i desteklediğini varsayıyorum, o yüzden herkes sadece en taşınabilir olanı kullanmalı. En küçük karakter sayısı!
Russ

@Russ, t=${t%?}Bourne değil , ancak bugünlerde bir Bourne kabuğuna rastlama ihtimaliniz yok. ${t%?}olsa diğerlerinde çalışır.
Stéphane Chazelas

Balık kabuğu seçeneği yok! Muhtemelen bugünlerde
ksh93'ten

@ rien333. Arayüzün biraz dengelenmesini beklerdim. fishiş devam ediyor. 2.3.0.0.2005 - Binaya tanıtılan 2.3.0 stringsoru-cevap sırasında serbest bırakılmadı. Üzerinde test ettiğim sürümde ihtiyacınız olacak string replace -r '(?s).\z' '' -- $t(ve bunu değiştirmek isteyeceklerini umuyorum, PCRE'ye ilettikleri bayrakları değiştirmeleri gerekiyor) veya daha kıvrımlı olanları. Ayrıca yeni satır karakterleriyle de ilgileniyor ve bunu da değiştirmeyi planladıklarını biliyorum.
Stéphane Chazelas 18:17

POSIX cevabı için oy verildi. Bash 3.2.57 (1) 'de çalıştığını doğruladı
Avindra Goolcharan

26

En taşınabilir ve en kısa cevap, neredeyse kesinlikle:

${t%?}

Bu bash, sh, kül, çizgi, busybox / kül, zsh, ksh, vb çalışır.

Eski okul kabuk parametresi genişlemesi kullanılarak çalışır. Spesifik olarak, glob kalıbıyla %eşleşen en küçük eşleşmeli parametrenin son ekini kaldırmayı belirtir.t? (yani: herhangi bir karakter).

(Daha fazla) daha ayrıntılı bir açıklama ve daha fazla arka plan için buradaki "En Küçük Ek Şablonunu Çıkarın" bölümüne bakın . Ayrıca, man bash"parametre genişletme" altındaki kabuğunuzun dokümanlarına bakın (örneğin :).


Not olarak, bunun yerine ilk karakteri kaldırmak isteseydiniz ${t#?},# dizenin önünden (önek) eşleşir (sonek).

Ayrıca değer belirterek hem olmasıdır %ve #var %%ve ##maç versiyonları, en uzun yerine kısa verili desen sürümünü. Her ikisi de ${t%%?}ve ${t##?}bu durumda tek operatörleri ile aynı şeyi yapacaktır, ancak (işe yaramaz ekstra karakter eklemeyin). Bunun nedeni verilen ?desenin sadece tek bir karakterle eşleşmesidir. Bir de karıştırın *olmayan bazı wildcard ile ve işler ile daha ilginç olsun %%ve ##.

Parametre genişlemelerini anlamak veya en azından onların varlığını bilmek ve nasıl görüneceğini bilmek, birçok lezzetin kabuk senaryolarını yazmak ve deşifre etmek için inanılmaz derecede faydalıdır. İyi ... onlar ... çünkü Parametre açılımları genellikle birçok kişiye oynamasından kabuk voodoo gibi bakmak vardır (eğer "parametresi genişleme" aramaya biliyorsanız oldukça iyi belgelenmiş olsa da) gizli kabuk büyü. Olsa da, bir kabuk takılı kaldığınızda kesinlikle alet kemeri içinde olması iyidir.


Kısa ve tatlı, hem MacOS hem de Linux'ta çalışıyor!
dbernard

18
t=lkj
echo ${t:0:${#t}-1}

0'dan bir dize uzunluğu -1 dize olsun. Bununla birlikte, bu çıkarma işleminin bash özgüdür ve diğer kabuklarda çalışmadığını unutmayın.

Örneğin, dashbile ayrıştırmak mümkün değil

echo ${t:0:$(expr ${#t} - 1)}

Örneğin, Ubuntu, /bin/sholupdash


15

Ayrıca headson karakter dışındakilerin hepsini yazdırmak için de kullanabilirsiniz .

$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin

Ancak ne yazık ki bazı sürümleri headlider -seçeneği içermemektedir . headOS X ile birlikte gelenler için durum bu.


5

Düzenli ifade kullanarak yapmak yeterince kolaydır:

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"

5

Bazı iyileştirmeler. Birden fazla karakter silmek için birden fazla soru işareti ekleyebilirsiniz. Örneğin, değişkenden son iki karakteri kaldırmak için: $SRC_IP_MSGkullanabilirsiniz:

SRC_IP_MSG=${SRC_IP_MSG%??}

4

Sadece bazı saf bash kullanımlarını tamamlamak için:

#!/bin/bash

# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"

İlk sözdizimi bir dizgeden bir alt dizgiyi alır, sözdizimi İkincisi için, 'satırın sonundan' anlamına gelen işareti görür ve sözdizimi
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}

Ve burada yukarıda belirtilenlerin iki kısa şekli var

echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"

Burada yine, %en kısa eşleşen kalıbı (burada '' ile değiştir '), yani en kısa eşleşen kalıbı (burada, burada ' \ ' kaçış alanı ' ' ile gösterilir) PARAMETER'in sonundan - burada STR olarak adlandırılan işarete dikkat edin.


1

Ayrıca komut satırında php veya shell script de kullanabiliriz . Bazen cerrahi ayrıştırma için kullanışlıdır.

php -r "echo substr('Hello', 0, -1);" 
// Output hell

Boru ile:

echo "hello" | php -r "echo substr(trim(fgets(STDIN)), 0, -1);"
// Output hell

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.