grepを使用して文字の位置を見つける方法は?


11

grepコマンドを使用して、文字列内の文字の位置を特定する必要があります。

たとえば、文字列はRAMSITALSKHMAN|1223333です。

grep -n '[^a-zA-Z0-9\$\~\%\#\^]'

|指定された文字列内のの位置を見つけるにはどうすればよいですか?


それはgrepである必要がありますか?
Braiam

回答:


29

を使用-bしてバイトオフセットを取得できます。これは、単純なテキストの位置と同じです(ただし、UTF-8などではありません)。

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|

上記では、-aスイッチを使用して、入力をテキストとして使用するようにgrepに指示しています。バイナリファイルを操作するときに必要であり-o、一致する文字のみを出力するスイッチ。

位置だけが必要な場合は、grepを使用して位置のみを抽出できます。

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14

奇妙な出力が表示される場合は、grepで色が有効になっているかどうかを確認してください。色を無効にするには--colors=never、grepに渡すか、grepコマンドの前に\(エイリアスを無効にします)を付けます。例:

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14

複数の一致を返す文字列の場合head -n1、最初の一致を取得するためにパイプスルーします。

上記の両方を使用していることに注意してください。後者は、実行可能ファイル(スクリプトなど)を介してgrepが「エイリアス」されている場合、エイリアスを使用する場合にのみ機能しません。


3
今度は2;)を検索してください
Izkata

@Izkataさん、ありがとうございます。私の投稿を少し更新し、欠落している帽子を追加しました^:)
runejuhl

1
どのバージョンのgrepを使用しましたか?私は出力0:|として取得します。0は、|見つかった行の先頭のバイト位置だからです。
Alex

Debianのストレッチから@AlexのGNU grepを:grep (GNU grep) 2.27。OS Xを使用していますか?
runejuhl

11

試してください:

printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'

出力:

15:|

これにより、index based-1の位置が得られます。


機能しない:(
user82782

1
@ user82782:どのコマンドを実行しましたか?それがうまくいかなかったのはどうしてですか?
cuonglm 2014

printf '%s\n' '|' | grep -o . | grep -n '|'期待どおり1ではなく0、印刷します。
l0b0 2014

1
@ l0b0:OPは、インデックスベース0または1が必要であることを知らせません
cuonglm

ソフトウェア開発者が期待することを意味するだけです。
l0b0 2014

8

シェルを使用している場合は、などの外部プロセスを生成する必要なく、純粋に組み込みの操作を使用できます。

$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$ 

これは、パラメータ展開を使用して、|任意の文字列によるfollowのすべての出現を削除し、それを一時変数に保存します。次に、一時変数の長さを測定してのインデックスを取得するだけです|

が元の文字列に存在ifするかどうかを確認していることに注意してください|。そうでない場合、一時変数は元の変数と同じになります。

また、これは0ベースのインデックスを提供し、そのインデックス|は通常、bash文字列にインデックスを付けるときに役立ちます。ただし、1から始まるインデックスが必要な場合は、次のようにすることができます。

$ echo $((${#tmp}+1))
15
$ 

1
おそらく最良の答えです。この構文は美しく、非常に高速で使いやすいので、意味を理解できます。コアまでの寿命が長い
vdegenne

4

awkのindex関数を使用して、一致が発生した位置を文字で返すことができます。

echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15

Perlのindex関数を使用してもかまわない場合、これは文字の0回または1回以上の出現を報告します。

echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'

読みやすくするためにのみ、パイプラインは2行に分割されています。

ターゲット文字が見つかる限りindex、ゼロ(0)を基準とする正の値を返します。したがって、文字列「abc | xyz | 123456 | zzz |」解析すると、位置0、4、8、15、19が返されます。


この用途では、awkはgrepよりも便利で簡単です。
Archemar

これは最初の位置のみを出力し、次のような文字列では機能しませんRAMSITALSKHMAN|1|223333
cuonglm

3

「expr match」または「expr index」を使用してそれを行うこともできます

expr match $ string $ substring $ substringはREです。

echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`

そして、上記は一致した部分文字列の長さを返すため、位置を示します。

しかし、インデックスを検索するためにより具体的には:

mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`

他の場所でコメントするのに十分な評判がありません。@Gnoucの答えが個人的に気に入りました。ただし、「expr」を使用して単純なことを実行できるときにawkを使用して複雑にする理由
bluefoggy

@kingsdebそれは単なる提案です。
Avinash Raj 14

@kingsdeb:(1)awkファイルのすべての行でこの情報をレポートするためにソリューションを簡単に変更できるため(ENDJRFergusonの回答から、本当に必要ではなかったを削除するだけで、Avinash Rajはすでにそれを実行しています) ; 一方、exprソリューションでそれを行うには、明示的なループを追加する必要があります(そして、Gnoucの答えはそれを行うために簡単に適応できません、私が見ることができます)、および(2)awkソリューションはすべての各行での一致は、expr解決策よりもいくぶん簡単です(実際、Avinash Raj'sでも既に行われています)。
G-Manは 'Reinstate Monica'を

なぜecho `...`ここで使うのですか?
ステファンChazelas

これは出力をここに表示するだけです
bluefoggy

2

別のawkコマンド

$ echo 'RAMSITALSKHMAN|1223333'| awk 'BEGIN{ FS = "" }{for(i=1;i<=NF;i++){if($i=="|"){print i;}}}'
15

フィールド区切り文字をnull文字列として設定することにより、awkはレコード内の個々の文字を個別のフィールドとして扱います。


2

いくつかの選択肢は次のとおりです。

Gnoucの答えに似ていますが、シェルがあります:

echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n | 
sh

sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'

sedし、dc場合によっては複数行にまたがります:

echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc

15

$IFS...

IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))

それはまた、どのようにあなたを教えてくれる多くのようにあります...

echo $(($#-1))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.