Bir kabuktaki bir dizenin son karakteri nasıl elde edilir?


126

Bir dizenin son karakterini elde etmek için aşağıdaki satırları yazdım:

str=$1
i=$((${#str}-1))
echo ${str:$i:1}

Şunlar için çalışır abcd/:

$ bash last_ch.sh abcd/
/

Şunun için çalışmazabcd* :

$ bash last_ch.sh abcd*
array.sh assign.sh date.sh dict.sh full_path.sh last_ch.sh

Bu Geçerli klasördeki dosyaları listeler .

Yanıtlar:


98

Değişkenlerinizi alıntı yapmanızın nedenlerinden biri budur:

echo "${str:$i:1}"

Aksi takdirde, bash değişkeni genişletir ve bu durumda yazdırmadan önce globling yapar. Parametreyi betiğe alıntı yapmak da daha iyidir (eşleşen bir dosya adınız olması durumunda):

sh lash_ch.sh 'abcde*'

Ayrıca bash başvuru kılavuzundaki genişletme sırasına bakın . Dosya adı genişletmeden önce değişkenler genişletilir.

Son karakteri elde etmek için, -1dizin olarak kullanmanız gerekir , çünkü negatif endeksler dizenin sonundan itibaren sayılır:

echo "${str: -1}"

İki nokta üst üste işaretinden ( :) sonraki boşluk GEREKLİDİR.

Bu yaklaşım boşluk olmadan işe yaramayacaktır.


62
BTW, negatif endeksler sağdan sayılır, bu yüzden "${1: -1}"yeterlidir.
choroba

7
Burada yorumlarda değil, resmi çözüm olarak yanıt vermelisiniz.
BMW

Bilginize: Bunu "tek satırlık" olarak da yapabilirsiniz echo "${str:$((${#str}-1)):1}". Bu, döndürülen son karakterleri de değiştirmenize olanak tanır. Bu benim için çalışıyor: bash v4.1.0 (1)
SaxDaddy

16
@ choroba'nın cevabı: Lanet boşluğa dikkat edin! Bu beni hep "${1:-1}
heyecanlandırıyor

192

@Perreal'e göre değişkenlerin alıntılanması önemlidir, ancak bu yazıyı yorumlarda eldeki soruya daha basit bir yaklaşım bulmadan önce 5 kez okudum çünkü ...

str='abcd/'
echo "${str: -1}"

Çıktı: /

str='abcd*'
echo "${str: -1}"

Çıktı: *

Yukarıda buna katılan herkese teşekkürler; Konu boyunca uygun şekilde + 1'ler ekledim!


25
Not: İçerideki boşluğa dikkat edin, boşluk ${std: -1}olmadan bu işe yaramaz. Bununla karşılaştım ve bunun ${std:~0}da işe yaradığını (boşluklu veya boşluksuz) buldum . Bunun belgelenmiş bir davranış olup olmadığından emin değilim, bakmaya zahmet etmedim.
Bart

4
belgelenmiştir. man bash diyor ki: a ile başlayan aritmetik ifadeler öncekinden boşlukla ayrılmalıdır: Varsayılan Değerleri Kullan genişlemesinden ayırt edilmelidir
mighq

3
Bu harika, paylaştığın için teşekkürler. BASH kılavuz sayfasını okumak neredeyse ezici olsa da, orada birkaç kez bulundum. Bence kabuk komut dosyası yazma lol etrafında bir üniversite kursu yapabilirler.
vites

3
Bu çözüm .sh, alınan karakteri bir değişkene atamaya çalışırken bir komut dosyasında çalışmaz . Örneğin declare LAST=$(echo "${str: -1}") Bu, şu
tarihten

3
düzenleyici sözdizimi denetimi bu alanı beğenmiyorsa deneyin${str:0-1}
ttt 9'17

37

Bunun çok eski bir konu olduğunu biliyorum, ancak kimse bana en net cevabın hangisi olduğunu söylemedi:

echo -n $str | tail -c 1

-nYankının sonunda bir satırsonu içermemesi için olduğunu unutmayın .


15
$ {Str: -1} 'den daha temiz olmaya yakın bile değil
shrewmouse

8
Bash-izm'e dayanmadığı için daha temizdir, bu nedenle herhangi bir Posix kabuğu ile çalışacaktır.
John Eikenberry

En "bashist" nedir? "$ {str: -1}" Ve ... En temiz olan nedir? "$ {str: -1}" Bash en iyisidir! :-)
Roger

Son karakterleri büyük bir dosyaya yazdırmaya çalışan herkes için bu işi benim için yaptı: cat kullanıcı / klasör / dosya.json | tail -c 1 1'i yazdırmak istediğiniz karakter sayısı ile değiştirebilirsiniz.
Diego Serrano

6

awk komut dosyası kullanan başka bir çözüm:

son 1 karakter:

echo $str | awk '{print substr($0,length,1)}'

son 5 karakter:

echo $str | awk '{print substr($0,length-5,5)}'

1
Operatörün istediği şey bu değil, ama bu bir dosyayla kullanılmak üzere bulduğum en iyi çözüm. Diğer yaklaşımların çoğu, aşağıdaki gibi bir dosyaya ulaşmak için işe yaramaz: cat file | awk '{print substr($0,length,1)}'Teşekkürler!
xmar

5

Şimdiye kadarki her yanıt, sorudaki "kabuk" kelimesini Bash'e eşit olduğunu ima ediyor.

Bunu standart bir Bourne kabuğunda şu şekilde yapabilirsiniz:

printf $str | tail -c 1

2
echo -nuser5394399 tarafından önerildiği gibi $str, özel format karakterleri içerdiğinde sorunları önler .
Conrad Meyer

-nAnahtar bir bashism olduğunu. Standart Bourne kabuğunda kısa çizgi vb. Olarak çalışmaz ... Cevabımın amacı buydu.
phep

1
Tam anlamıyla bir basizm değildir, ancak POSIX bunun uygulama tanımlı olduğunu tanır ("İlk işlenen -n ise veya işlenenlerden herhangi biri bir <ters eğik çizgi> karakteri içeriyorsa, sonuçlar uygulama tanımlıdır"). Cevabınız bunun yerine printf "%s" "$str" | ...:-) ile sabitlenebilir .
Conrad Meyer

4

Tek satır:

${str:${#str}-1:1}

Şimdi:

echo "${str:${#str}-1:1}"

1
Neden iki çift parantez kullanıyorsunuz? Ayrıca, 4.2'den beri, hızlı kaydırmanın cevabında gösterildiği gibi negatif ofsetleri kullanabilirsiniz: echo "${str: -1}"yeterlidir ( :ve arasındaki boşluğa dikkat edin -).
gniourf_gniourf

Aritmetik işlemler için iki çift parantez kullanılır
Eduardo Cuomo

Hayır. Lütfen okuyacağınız kılavuzun ilgili bölümüne bakın : uzunluk ve ofset aritmetik ifadelerdir (bkz. Kabuk Aritmetiği ); dolayısıyla zaten kabuk aritmetiğindesiniz ve herhangi bir paranteze ihtiyacınız yok. Ayrıca, söylediklerin doğru olsaydı, aritmetik bir genişlemeye sahip olmak daha mantıklı olurdu $((...)).
gniourf_gniourf

@gniourf_gniourf haklısın! Şimdi önceki sorunuzu anlıyorum. Cevap güncellendi
Eduardo Cuomo

4

Deneyin:

"${str:$((${#str}-1)):1}"

Örneğin:

someone@mypc:~$ str="A random string*"; echo "$str"
A random string*
someone@mypc:~$ echo "${str:$((${#str}-1)):1}"
*
someone@mypc:~$ echo "${str:$((${#str}-2)):1}"
g

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.