Kabuk komut dosyasında bir dizenin ilk iki karakteri nasıl çıkarılır?


123

Örneğin, verilen:

USCAGoleta9311734.5021-120.1287855805

Sadece şunu çıkarmak istiyorum:

US

6
Herkese teşekkürler. "Cut -c1-2" yi kullandım, dürüst olmak gerekirse "cut" ın orada olduğunu bile bilmiyordum. Komut satırında oldukça deneyimli olduğumu söylemek isterim - ama görünüşe göre öğrenecek çok şeyim var.
Greg

1
@Greg, kesmenin ayrı bir süreç olarak çalıştırıldığının farkında olun - cevabımda onunla birlikte yayınladığım dahili bash çözümünden daha yavaş olacak. Büyük veri kümelerini işlemediğiniz sürece bu herhangi bir fark yaratmaz, ancak bunu aklınızda tutmanız gerekir.
paxdiablo

Düzenleme Aslında, bu kod satırının muhtemelen rapor başına yaklaşık 50.000 kez çalıştırılacağını düşünüyorum. Bu yüzden dahili Bash yöntemini kullanabilirim - bu da sizin de söylediğiniz gibi çok ihtiyaç duyulan kaynakları koruyacaktır.
Greg

Yanıtlar:


180

Muhtemelen en etkili yöntem, eğer bashkabuğu kullanıyorsanız (ve yorumlarınıza göre öyle görünüyorsunuz), parametre genişletmenin alt dize varyantını kullanmaktır:

pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}" ; echo "${short}"
US

Bu, öğesinin shortilk iki karakteri olacak şekilde ayarlanacaktır long. Eğer longiki karakterden kısa, shortbuna aynı olacaktır.

Bu kabuk içi yöntem, işlem yaratma ek yükü olmadığından, bunu çok yapacaksanız genellikle daha iyidir (bahsettiğiniz rapor başına 50.000 kez). Harici programları kullanan tüm çözümler bu ek yükten zarar görecektir.

Ayrıca minimum bir uzunluk sağlamak istiyorsanız, elinizden önce aşağıdaki gibi bir şeyle doldurabilirsiniz:

pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}" ; echo "${short}"
A.

Bu, iki karakterden daha kısa olan herhangi bir şeyin sağ tarafa noktalarla (veya başka bir şey, yalnızca yaratırken kullanılan karakteri değiştirerek) doldurulmasını sağlayacaktır tmpstr. Buna ihtiyacın olup olmadığı belli değil ama eksiksiz olması için onu koyacağımı düşündüm.


Bununla birlikte, bunu harici programlarla yapmanın birçok yolu vardır (örneğin, size ulaşamıyorsanız bash), bunlardan bazıları:

short=$(echo "${long}" | cut -c1-2)
short=$(echo "${long}" | head -c2)
short=$(echo "${long}" | awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}" | sed 's/^\(..\).*/\1/')

İlk ikisi ( cutve head) tek satırlık bir dize için aynıdır - temelde ikisi de size yalnızca ilk iki karakteri geri verir. cutSize her satırın headilk iki karakterini verecek ve size tüm girdinin ilk iki karakterini verecek olmaları bakımından farklılık gösterirler.

Üçüncüsü awk, ilk iki karakteri çıkarmak için alt dize işlevini kullanır ve dördüncü , ilk iki karakteri yakalamak ve tüm satırı onlarla değiştirmek için sedyakalama gruplarını ( ()ve kullanarak \1) kullanır . İkisi de birbirine benzer cut- girdideki her satırın ilk iki karakterini sunarlar.

Girişinizin tek bir satır olduğundan eminseniz, bunların hiçbirinin önemi yoktur, hepsinin aynı etkisi vardır.


Daha doğrusu kullanmak printf '%s'yerine echo: dizede garip karakter vardır durumunda stackoverflow.com/a/40423558/895245 : POSIX'deki için takıntılı head -cPOSIX değil, cut -cve awk substrvardır sed \1emin.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 printf kullanarak, ek bir programa bile ihtiyacınız yok. Cevabımı gör .
bschlueter

60

en kolay yol

${string:position:length}

Bu, $lengthalt dizeyi, $stringadresinden çıkarır $position.

Bu yerleşik bir bash olduğundan awk veya sed gerekli değildir.


Bu, alt dizeyi elde etmenin kısa, tatlı ve en kolay yoludur.
ani627

34

Birkaç iyi yanıtlar ele verdik ve kendime yerleşik Bash ile gitmek istiyorum ama sorulduğunda beri sedve awkve ( neredeyse onlara göre) hiç kimse sunulan çözümler, sana bunları sunuyoruz:

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}'

ve

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/'

awkBiri oldukça açık olmalı, ama burada bir açıklamasını aşağıda sedone:

  • "s /" yerine koyun
  • "^" satırının başından başlayıp ".." herhangi bir karakterden sonra gelen herhangi iki karakterden oluşan "()" grubu. sıfır veya daha fazla kez tekrarlanan "*" (bazı özel karakterlerden kaçınmak için ters eğik çizgiler gereklidir)
  • "/" ile birinci (ve yalnızca bu durumda) grubun içeriği (burada ters eğik çizgi, eşleşen bir alt ifadeye atıfta bulunan özel bir çıkış noktasıdır)
  • bitti "/"

1
Awk dizgelerinde dizin 1'den başlar, bu yüzden kullanmalısınız substr($0,1,2).
Isaac

8

İçindeyseniz şunu bashsöyleyebilirsiniz:

bash-3.2$ var=abcd
bash-3.2$ echo ${var:0:2}
ab

Bu tam da ihtiyacınız olan şey olabilir ...


bu en kolay ve en basit cevap! bir cazibe gibi çalıştı
aloha

7

Sadece grep:

echo 'abcdef' | grep -Po "^.."        # ab

İhtiyaçlarıma uyuyor. Kısaltmak için -Pseçeneği kaldırabilirsiniz . Tüm normal ifadeler bu kalıbı anlayacaktır.
datashaman

6

Şunları kullanabilirsiniz printf:

$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$original"
US

5

colrm - bir dosyadan sütunları kaldırır

İlk iki karakteri bırakmak için, 3'ten başlayarak sütunları kaldırmanız yeterlidir.

cat file | colrm 3

4

Gerçekten oldukça geç ama işte burada

sed 's/.//3g'

Veya

awk NF=1 FPAT=..

Veya

perl -pe '$_=unpack a2'

2

Kabuk komut dosyası kullanmak istiyorsanız ve posix olmayan uzantılara (sözde bashismler gibi) güvenmiyorsanız, grep, sed, cut, awk vb. Gibi harici araçların çatallanmasını gerektirmeyen teknikleri kullanabilirsiniz. betiğinizi daha az verimli hale getirin. Belki de verimlilik ve posix taşınabilirliği kullanım durumunuzda önemli değildir. Ancak böyle olması durumunda (veya sadece iyi bir alışkanlık olması durumunda), bir kabuk değişkeninin ilk iki karakterini çıkarmak için aşağıdaki parametre genişletme seçeneği yöntemini kullanabilirsiniz:

$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab

Bu , ilk iki karakteri (bu kısımdır) kaldırmak için "en küçük önek" parametre genişletmesini${var#??} , ardından "en küçük son ek" parametre genişletmesini ( ${var%parça) ilk iki karakter hariç tümü dizesini orijinalden kaldırmak için kullanır değer.

Bu yöntem daha önce "Shell = Değişken # ile başlayıp başlamadığını kontrol et" sorusuna verilen yanıtta açıklanmıştır . Bu cevap ayrıca, buradaki orijinal soru için geçerli olandan biraz farklı bir bağlamda kullanılabilecek birkaç benzer parametre genişletme yöntemini de açıklamaktadır.


En iyi cevap, en üstte olmalıdır. çatal yok, eziyet yok. kısa çizgi gibi küçük kabuklarla bile çalışır.
Mayıs'ı 07

1

Sisteminiz farklı bir kabuk kullanıyorsa (değil bash), ancak sisteminizde varsa bash, bir değişkenle bashçağırarak doğal dize manipülasyonunu kullanmaya devam edebilirsiniz bash:

strEcho='echo ${str:0:2}' # '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"

Bu , ana cevapla aynı yöntemi kullanır , yalnızca bashzaten kullanmıyorsanız çağırır.
palswim

Ne yazık ki, bu, başka bir süreci çağırmanın tüm ek yüküyle birlikte gelir, ancak bazen bu ek yükün basitlik ve tanıdıklık kadar önemli olmadığı söylenebilir.
palswim

1

Sırf eğlence uğruna, fazla karmaşık ve yararsız olmalarına rağmen bunlardan bahsedilmediğini birkaçını ekleyeceğim:

head -c 2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

echo 'USCAGoleta9311734.5021-120.1287855805' | dd bs=2 count=1 status=none

sed -e 's/^\(.\{2\}\).*/\1/;' <( echo 'USCAGoleta9311734.5021-120.1287855805')

cut -c 1-2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

python -c "print(r'USCAGoleta9311734.5021-120.1287855805'[0:2])"

ruby -e 'puts "USCAGoleta9311734.5021-120.1287855805"[0..1]'


0

dizgim = USCAGoleta9311734.5021-120.1287855805 ise

print substr(mystring,0,2)

ABD'yi yazdıracaktı

burada 0 başlangıç ​​konumu ve 2 çok sayıda karakterin nasıl okunacağıdır


Söyleyin ... bu GW-BASIC değil mi? Oh, bekle, bu awk. Üzgünüm, ilk başta anlayamadım.
sonraki duyuruya kadar duraklatıldı.

0

Bu senin peşinde mi?

my $string = 'USCAGoleta9311734.5021-120.1287855805';

my $first_two_chars = substr $string, 0, 2;

ref: substr


1
Bunu kabuğundan çağırması muhtemel olduğu düşünüldüğünde, daha iyi bir formperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
Chas. Owens
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.