Yanıtlar:
-bBasit metin konumu ile aynı olan bayt uzaklığını elde etmek için kullanabilirsiniz (ancak UTF-8 veya benzeri için değil).
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|
Yukarıda, -agrep'e girişi metin olarak kullanmasını söylemek için anahtarı kullanıyorum; ikili dosyalar üzerinde çalışırken ve -oyalnızca eşleşen karakter (ler) in çıkış anahtarı kullanılır.
Yalnızca konumu istiyorsanız, grep komutunu yalnızca konumu çıkarmak için kullanabilirsiniz:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14
Tuhaf bir çıktı alırsanız, grep'in renklerin etkin olup olmadığını kontrol edin. --colors=neverGrep'e ileterek veya grep komutunun önüne bir ön ek uygulayarak \(diğer adları devre dışı bırakacak) renkleri devre dışı bırakabilirsiniz, örneğin:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14
Birden çok eşleşme döndüren bir dize head -n1için, ilk eşleşmeyi almak üzere geçiş yapın.
Her ikisini de yukarıda kullandığımı ve grep yalnızca bir takma ad (komut dosyası veya başka bir yolla), yalnızca takma adlar kullanarak "diğer adı" ise çalışmadığını unutmayın.
2;)
^
0:|0 satırın başlangıcına bayt pozisyonu olduğu için output-- olarak |bulunmuştur.
grep (GNU grep) 2.27. Belki OS X mi kullanıyorsunuz?
Deneyin:
printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'
çıktı:
15:|
Bu size dizin tabanlı-1 olan konumu verecektir.
printf '%s\n' '|' | grep -o . | grep -n '|'baskılar 1, değil 0beklendiği gibi.
Bash kabuğunu kullanıyorsanız, grep veya awk gibi harici süreçleri ortaya çıkarmaya gerek kalmadan tamamen yerleşik işlemleri kullanabilirsiniz :
$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$
Bu, herhangi bir dizeyle aşağıdaki tüm oluşumları kaldırmak ve bunu geçici bir değişkene kaydetmek için bir parametre genişletmesi kullanır |. Bu sadece endeksi elde etmek için geçici değişkenin uzunluğunu ölçmektir |.
Dikkat ifedin,| orijinal dizede hiç yoktur. Eğer değilse, geçici değişken orjinal ile aynı olacaktır.
Bu ayrıca |, bash dizelerini dizine eklerken genellikle yararlı olan sıfır temelli dizini de sağlar . Ancak, tek tabanlı dizine ihtiyacınız varsa, bunu yapabilirsiniz:
$ echo $((${#tmp}+1))
15
$
Eşleşmenin indexgerçekleştiği karakterlerde konumu döndürmek için awk işlevini kullanabilirsiniz :
echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15
Perl indexişlevini kullanmanın bir sakıncası yoksa , bu, bir karakterin sıfır, bir veya daha fazla tekrarını bildirmeyi işler:
echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'
Sadece okunabilirlik için, boru hattı iki hatta ayrılmıştır.
Hedef karakter bulunduğu sürece index, sıfır (0) temelinde pozitif bir değer döndürür. Bu nedenle, "abc | xyz | 123456 | zzz |" dizesi ayrıştırıldığında 0, 4, 8, 15 ve 19 konumlarını döndürür.
RAMSITALSKHMAN|1|223333
Bunu "ifade eşleşmesi" veya "ifade dizini" kullanarak da yapabiliriz
expr $ string $ substring ile eşleşir; burada $ substring bir RE'dir.
echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`
Ve yukarıda size pozisyonu verecektir, çünkü eşleşen alt dizenin uzunluğunu döndürür.
Ancak arama dizini için daha spesifik olmak gerekirse:
mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`
awkçözümler bir dosyanın her satırında bu bilgileri rapor etmek için önemsiz bir şekilde değiştirilebilir (tek yapmanız ENDgereken, gerçekten gerekli olmayan, JRFerguson'un cevabından kaldırmaktır ve Avinash Raj'ın zaten yaptığı) ; bununla birlikte, bunu exprçözümle yapmak için, açık bir döngü eklemeniz gerekir (ve Gnouc'un cevabı bunu yapabilmek için kolayca uyarlanamaz, görebiliyorum) ve (2) awkçözümler tüm raporları bildirmek için uyarlanabilir. her satırdaki exprçözümden biraz daha kolay eşleşir (aslında, Avinash Raj'ın bunu zaten yaptığı gibi).
echo `...`burada kullanasýn ki ?
$ echo 'RAMSITALSKHMAN|1223333'| awk 'BEGIN{ FS = "" }{for(i=1;i<=NF;i++){if($i=="|"){print i;}}}'
15
Alan ayırıcısını boş dize olarak ayarlayarak awk, kayıttaki tek tek karakteri ayrı alanlar olarak döndürür.
bazı alternatifler:
Gnouc'un cevabına benzer, ancak kabukla:
echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n |
sh
sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'
birden çok satıra sahip sedve dcmuhtemelen birden fazla satır içerebilir:
echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc
15
ile $IFS...
IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))
Bu aynı zamanda kaç tane var olduğunu da söyleyecektir ...
echo $(($#-1))