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?
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:
Bir POSIX kabuğunda, sözdizimi ${t:-2}
farklı bir şey ifade eder - t
eğer t
ayarlanmış 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
, bash
ya 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 i
arasında dize ijk
).
Daha fazla bilgi için Bash Referans Kılavuzunun Shell Parametre Genişletme bölümüne bakın:
${parameter%word}
en kısa son ek desen eşleştirmesini kaldırır word
- bkz. Parametre Genişletme bölümüman bash
İle bash
yukarı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.5
OS X'te), kolonların arasında ve sonrasında boşluk bırakmanız gerektiğine dikkat edin:
${var: : -1}
bash
sü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ü. : - /
${var:offset:lenght}
yalnızca içeriye eklendi bash 4.2
. Belki OSX kendi yamasını ekler bash
.
son n
karakterleri, kullanılmayan bir satırdan kaldırmak içinsed
VEYAawk
:
> echo lkj | rev | cut -c (n+1)- | rev
yani son karakteri silebilirsiniz one character
kullanarak :
> echo lkj | rev | cut -c 2- | rev
> lk
dan rev
man:
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
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.
Kabuğa bağlı olarak birkaç seçenek:
t=${t%?}
t=`expr " $t" : ' \(.*\).'`
t=${t[1,-2]}
t=${t:0:-1}
t=${t:0:${#t}-1}
t=${t/%?}
t=${t/~(E).$/}
@ {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) ).
expr
Varyantı varsayar $t
birden fazla satır karakteriyle bitmiyor. Ayrıca, sonuçta ortaya çıkan dizge bitmişse 0
( 000
veya hatta -0
bazı uygulamalarda) sıfır olmayan bir çıkış durumu döndürür . Dize geçersiz karakterler içeriyorsa, beklenmeyen sonuçlar verebilir.
t=${t%?}
Bourne değil , ancak bugünlerde bir Bourne kabuğuna rastlama ihtimaliniz yok. ${t%?}
olsa diğerlerinde çalışır.
fish
iş devam ediyor. 2.3.0.0.2005 - Binaya tanıtılan 2.3.0 string
soru-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.
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.
Ayrıca head
son 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 head
lider -
seçeneği içermemektedir . head
OS X ile birlikte gelenler için durum bu.
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.