Saya perlu mengidentifikasi posisi karakter dalam string menggunakan perintah grep.
Contoh, stringnya adalah RAMSITALSKHMAN|1223333
.
grep -n '[^a-zA-Z0-9\$\~\%\#\^]'
Bagaimana cara menemukan posisi |
dalam string yang diberikan?
Saya perlu mengidentifikasi posisi karakter dalam string menggunakan perintah grep.
Contoh, stringnya adalah RAMSITALSKHMAN|1223333
.
grep -n '[^a-zA-Z0-9\$\~\%\#\^]'
Bagaimana cara menemukan posisi |
dalam string yang diberikan?
Jawaban:
Anda dapat menggunakan -b
untuk mendapatkan byte offset, yang sama dengan posisi untuk teks sederhana (tetapi tidak untuk UTF-8 atau serupa).
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|
Di atas, saya menggunakan -a
saklar untuk memberi tahu grep untuk menggunakan input sebagai teks; diperlukan saat beroperasi pada file biner, dan -o
sakelar untuk hanya menampilkan karakter yang cocok.
Jika Anda hanya menginginkan posisi, Anda dapat menggunakan grep untuk mengekstrak hanya posisi:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14
Jika Anda mendapatkan output aneh, periksa untuk melihat apakah grep memiliki warna yang diaktifkan. Anda dapat menonaktifkan warna dengan meneruskan --colors=never
ke grep, atau dengan mengawali perintah grep dengan \
(yang akan menonaktifkan alias apa pun), misalnya:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14
Untuk string yang mengembalikan banyak kecocokan, sambungkan head -n1
untuk mendapatkan kecocokan pertama.
Perhatikan bahwa saya menggunakan keduanya di atas, dan perhatikan bahwa yang terakhir tidak akan bekerja jika grep "alias" melalui executable (skrip atau sebaliknya), hanya ketika menggunakan alias.
2
;)
^
:)
0:|
output-- karena 0 adalah posisi byte dari awal baris di mana |
ditemukan.
grep (GNU grep) 2.27
. Apakah Anda mungkin menggunakan OS X?
Mencoba:
printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'
keluaran:
15:|
Ini akan memberi Anda posisi dengan indeks berbasis-1.
printf '%s\n' '|' | grep -o . | grep -n '|'
cetakan 1
, tidak 0
seperti yang diharapkan.
Jika Anda menggunakan bash shell, Anda dapat menggunakan operasi yang murni bawaan tanpa perlu memunculkan proses eksternal seperti grep atau awk :
$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$
Ini menggunakan ekspansi parameter untuk menghapus semua kemunculan |
diikuti oleh string apa pun dan menyimpannya dalam variabel sementara. Maka itu hanya masalah mengukur panjang variabel sementara untuk mendapatkan indeks |
.
Perhatikan if
memeriksa apakah |
ada sama sekali dalam string asli. Jika tidak maka variabel sementara akan sama dengan yang asli.
Perhatikan juga ini memberikan indeks berbasis nol |
yang umumnya berguna saat mengindeks string bash. Namun jika Anda memerlukan indeks berbasis satu, maka Anda dapat melakukan ini:
$ echo $((${#tmp}+1))
15
$
Anda dapat menggunakan index
fungsi awk untuk mengembalikan posisi dalam karakter di mana pertandingan terjadi:
echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15
Jika Anda tidak keberatan menggunakan fungsi Perl index
, ini menangani pelaporan nol, satu atau lebih kemunculan karakter:
echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'
Untuk keterbacaan, hanya, pipa telah dibagi menjadi dua garis.
Selama karakter target ditemukan, index
mengembalikan nilai positif berdasarkan nol (0). Karenanya, string "abc | xyz | 123456 | zzz |" ketika parsed mengembalikan posisi 0, 4, 8, 15 dan 19.
RAMSITALSKHMAN|1|223333
Kami juga dapat melakukannya menggunakan "expr match" atau "expr index"
expr cocokkan $ string $ substring di mana $ substring adalah RE.
echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`
Dan di atas akan memberi Anda posisi karena mengembalikan panjang substring yang cocok.
Tetapi untuk lebih spesifik untuk indeks pencarian:
mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`
awk
solusi sepele dapat dimodifikasi untuk melaporkan informasi ini pada setiap baris file (yang harus Anda lakukan adalah menghapus END
, yang tidak pernah benar-benar diperlukan, dari jawaban JRFerguson, dan Avinash Raj sudah melakukannya) ; sedangkan, untuk melakukan itu dengan expr
solusinya, Anda perlu menambahkan loop eksplisit (dan jawaban Gnouc tidak mudah diadaptasi untuk melakukan itu sama sekali, yang bisa saya lihat), dan (2) awk
solusi dapat disesuaikan untuk melaporkan semua cocok di setiap baris agak lebih mudah daripada expr
solusi (pada kenyataannya, Avinash Raj sudah melakukannya juga).
echo `...`
sini?
$ echo 'RAMSITALSKHMAN|1223333'| awk 'BEGIN{ FS = "" }{for(i=1;i<=NF;i++){if($i=="|"){print i;}}}'
15
Dengan mengatur pemisah bidang sebagai string nol, awk mengubah karakter individu dalam catatan sebagai bidang yang terpisah.
beberapa alternatif termasuk:
mirip dengan jawaban Gnouc, tetapi dengan shell:
echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n |
sh
sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'
dengan sed
dan dc
mungkin menjangkau beberapa baris:
echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc
15
dengan $IFS
...
IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))
Itu juga akan memberi tahu Anda ada berapa banyak seperti ...
echo $(($#-1))