Antworten:
Mit können -b
Sie den Byte-Offset ermitteln, der der Position für einfachen Text entspricht (jedoch nicht für UTF-8 oder ähnliches).
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|
Oben benutze ich den -a
Schalter, um grep anzuweisen, die Eingabe als Text zu verwenden. erforderlich, wenn Binärdateien bearbeitet werden und der -o
Schalter nur die übereinstimmenden Zeichen ausgibt.
Wenn Sie nur die Position möchten, können Sie grep verwenden, um nur die Position zu extrahieren:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14
Wenn Sie eine seltsame Ausgabe erhalten, prüfen Sie, ob in grep Farben aktiviert sind. Sie können Farben deaktivieren, indem Sie --colors=never
an grep übergeben oder dem Befehl grep ein \
(das alle Aliase deaktiviert) voranstellen. Beispiel:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14
Für eine Zeichenfolge, die mehrere Übereinstimmungen zurückgibt, leiten head -n1
Sie die Pipe durch , um die erste Übereinstimmung zu erhalten.
Beachten Sie, dass ich oben beides verwende und dass letzteres nicht funktioniert, wenn grep über eine ausführbare Datei (Skript oder auf andere Weise) "aliasiert" ist, nur wenn Aliase verwendet werden.
2
;)
^
:)
0:|
als output-- weil 0 die Byte-Position des Zeilenanfangs |
ist, an der gefunden wird.
grep (GNU grep) 2.27
. Verwenden Sie vielleicht OS X?
Versuchen:
printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'
Ausgabe:
15:|
Dies gibt Ihnen die Position mit Index-1.
printf '%s\n' '|' | grep -o . | grep -n '|'
druckt 1
nicht 0
wie erwartet.
Wenn Sie die Bash- Shell verwenden, können Sie rein integrierte Operationen verwenden, ohne externe Prozesse wie grep oder awk starten zu müssen :
$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$
Hierbei wird eine Parametererweiterung verwendet , um alle Vorkommen von |
Folgen durch eine beliebige Zeichenfolge zu entfernen und diese in einer temporären Variablen zu speichern. Es geht dann nur noch darum, die Länge der temporären Variablen zu messen, um den Index von zu erhalten |
.
Beachten Sie, dass if
überprüft wird, ob das |
überhaupt in der ursprünglichen Zeichenfolge vorhanden ist. Ist dies nicht der Fall, entspricht die temporäre Variable dem Original.
Beachten Sie auch, dass dies den auf Null basierenden Index liefert, der |
im Allgemeinen beim Indizieren von Bash-Strings nützlich ist. Wenn Sie jedoch einen einseitigen Index benötigen, können Sie dies tun:
$ echo $((${#tmp}+1))
15
$
Sie können die awk- index
Funktion verwenden, um die Position in Zeichen zurückzugeben, an der die Übereinstimmung auftritt:
echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15
Wenn es Ihnen nichts ausmacht, die Perl- index
Funktion zu verwenden, werden keine, ein oder mehrere Vorkommen eines Zeichens gemeldet:
echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'
Nur aus Gründen der Lesbarkeit wurde die Pipeline auf zwei Zeilen aufgeteilt.
Solange das Zielzeichen gefunden wird, wird index
ein positiver Wert basierend auf Null (0) zurückgegeben. Daher ist die Zeichenfolge "abc | xyz | 123456 | zzz |" Beim Parsen werden die Positionen 0, 4, 8, 15 und 19 zurückgegeben.
RAMSITALSKHMAN|1|223333
Wir können es auch mit "expr match" oder "expr index" machen
Ausdruck stimmt mit $ string $ substring überein, wobei $ substring eine RE ist.
echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`
Und oben geben Sie die Position an, da sie die Länge der übereinstimmenden Teilzeichenfolge zurückgibt.
Genauer gesagt für den Suchindex:
mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`
awk
Lösungen trivial modifiziert werden können, um diese Informationen in jeder Zeile einer Datei zu melden (alles, was Sie tun müssen, ist das END
, was nie wirklich nötig war, aus JRFergusons Antwort zu entfernen , und Avinash Rajs tut es bereits) ; expr
Um dies mit der Lösung zu tun, müssten Sie eine explizite Schleife hinzufügen (und die Antwort von Gnouc ist, wie ich sehen kann, nicht leicht anpassbar, um dies überhaupt zu tun), und (2) die awk
Lösungen können angepasst werden, um alle zu melden passt in jeder Zeile etwas leichter als die expr
Lösung (tatsächlich macht Avinash Rajs das auch schon).
echo `...`
hier verwenden?
$ echo 'RAMSITALSKHMAN|1223333'| awk 'BEGIN{ FS = "" }{for(i=1;i<=NF;i++){if($i=="|"){print i;}}}'
15
Indem Sie das Feldtrennzeichen als Nullzeichenfolge festlegen, wandelt awk einzelne Zeichen im Datensatz als separate Felder um.
Einige Alternativen sind:
Ähnlich wie Gnoucs Antwort, aber mit der Shell:
echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n |
sh
sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'
mit sed
und dc
möglicherweise über mehrere Zeilen:
echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc
15
mit $IFS
...
IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))
Das wird dir auch sagen, wie viele es sind wie ...
echo $(($#-1))