Wie finde ich den Index eines Wortes in einer Zeichenfolge in Bash?

10

Im Bash-Skript

Ich habe eine Zeichenfolge, die mehrere Wörter enthält, die durch ein oder mehrere Leerzeichen getrennt sind. dh:

Name   Age Sex  ID         Address

Wenn ich eines der Wörter finden möchte, zum Beispiel den Index des Wortes "Alter", wie kann ich das tun?

Gibt es einen Befehl, der die Indexnummer des gewünschten Wortes direkt zurückgibt?

Vielen Dank.

G3Y
quelle
Muss die Lösung ausschließlich in Bash sein? Oder kann awk, grep usw. verwendet werden?
Jftuga
In Verbindung stehender Beitrag: Wie drucke ich bestimmte Spalten nach Namen?
zx8754

Antworten:

12

Bash führt die Wortaufteilung in Zeichenfolgen von selbst durch - in der Tat meistens, um dies zu vermeiden, ist ein Problem, und der Grund für das Zitieren ist so wichtig. In Ihrem Fall ist es einfach, dies zu nutzen: Fügen Sie Ihren String einfach in ein Array ein, ohne ihn zu zitieren. Bash verwendet die Wortaufteilung, um die einzelnen Elemente zu trennen. Angenommen, Ihre Zeichenfolge ist in der Variablen gespeichert $str.

ar=($str) # no quotes!

gibt ein Array von 5 Elementen zurück. Ihr Array-Index ist Ihr Wortindex (von 0 bis hoch, wie in den meisten Skript- und Programmiersprachen), dh auf "Alter" wird mit zugegriffen

${ar[1]}  # 0 => Name, 1 => Age, 2 => Sex, 3 => ID, 4 => Address

oder, wenn Sie den Elementindex nach Inhalt suchen müssen, durchlaufen Sie das Array, d. h

function el_index {
    cnt=0; for el in "${ar[@]}"; do
        [[ $el == "$1" ]] && echo $cnt && break
        ((++cnt))
    done
}
el_index "Age" # => 1
kopischke
quelle
wow ... ich wusste nicht, dass es ohne die Anführungszeichen ein Array sein würde. Vielen Dank!
G3Y
4
$ export FOO="Name   Age Sex  ID         Address"

Ersetzen Sie * Alter durch Alter - dies entfernt alles vor "Alter":

$ echo ${FOO/*Age/Age}
Age Sex ID Address

Holen Sie sich alles vor "Alter"

$ echo ${FOO/Age*/}
Name

Ermitteln Sie die Länge dieser Zeichenfolge (dies ist der Index für "Alter"):

$ BEGIN=${FOO/Age*/}
$ echo ${#BEGIN}
7
user1034081
quelle
Beantwortet die Frage nicht, aber wow! Schicker Trick. Es funktioniert sogar in Asche und mit eingebetteten Variablen: export L='debug info warn error'; export GTE='warn'; echo ${L/*${GTE}/${GTE}}Gibt 'warn error' aus
Steve Tarver
0

Wenn Sie bash nicht unbedingt verwenden müssen, sondern andere Programme verwenden können, die üblicherweise auf Systemen mit bash zu finden sind, können Sie Folgendes verwenden:

echo "Name   Age Sex ID  Addr" | python -c 'print(raw_input().index("Age"))+1'

Python startet die String-Indizierung bei Null, daher habe ich am Ende des Befehls +1 hinzugefügt.

jftuga
quelle
0

Sie können den nativen regulären Ausdruck von bash verwenden

# a function to print the index of a field and its name
printIx() { 
  for ((l=0,i=1;i<$1;i++)) ;do 
     ((l+=${#BASH_REMATCH[i]}))
  done
  printf '%3s %s\n' $l "$2"
}

#   Using a zero based index
#   "0----+----1----+----2----+----3----+----4"
str="  Name   Age Sex  ID         Address   "

if [[ $str =~ ^(\ *)(Name)(\ +)(Age)(\ +)(Sex)(\ +()ID)(\ +)(Address)\ *$ ]] ;then
  F=(Name Age Sex ID Address)
  f=(   2   4   6  8      10)  # regex back-references
  for ((g=0;g<${#f[@]};g++)) ;do
     printIx  ${f[g]} "${F[g]}"
  done 
fi

Ausgabe

  2 Name
  9 Age
 13 Sex
 20 ID
 29 Address
Peter.O
quelle
0

Hinweis : Angenommen, Sie möchten mit Index wissen, um welches Wort es sich handelt (ab 0) und nicht um welches Zeichen in der Zeichenfolge, mit dem das Wort beginnt. Andere Antworten sprechen letztere an.

Nicht dass ich es wüsste, aber du kannst eins machen. Zwei Tricks:

  1. Verwenden Sie die angeborenen Fähigkeiten des for- Konstrukts, um eine nicht zitierte Eingabe durch Leerzeichen aufzuteilen.
  2. Behandeln Sie den Fall, in dem Sie die gewünschte Spalte nicht finden können. In diesem Fall habe ich beschlossen, den gefundenen Index an stout zu senden und den Statuscode anzeigen zu lassen, ob der Fund erfolgreich war. Es gibt andere Möglichkeiten.

Code:

#!/bin/bash
find_index() {
    local str=$1
    local search=$2
    let local n=0
    local retval=1 # here, 1 is failure, 0 success
    for col in $str; do # $str unquoted -> whitespace tokenization!
    if [ $col = $search ]; then
        echo $n
        retval=0
        break
    else
        ((n++))
    fi
    done
    return $retval
}

test="Name   Age Sex  ID         Address"
idx=`find_index "$test" Age`
if [ $? -ne 0 ]; then
    echo "Not found!"
else
    echo "Found: $idx"
fi
Owen S.
quelle
0

Versuchen Sie den folgenden Javascript-Oneliner in einer Shell (verwenden Sie die Javascript-Shell):

$ js <<< "x = 'Name   Age Sex  ID         Address'; print(x.indexOf('Age'));"
7

Oder mit einem Here-Doc:

js <<EOF
x = 'Name   Age Sex  ID         Address';
print(x.indexOf('Age'));
EOF
Gilles Quenot
quelle
0

Ich habe eine Lösung gefunden, die gut funktioniert.

$ string = 'jetzt ist die Zeit'
$ buf = die Ausgabe von $ {string # * the}
$ echo $ buf
: die Zeit
$ index = $ (($ {# string} - $ {# buf} + 1))
$ echo $ index
output: 8 -> index des ersten wortes "the"

Es funktioniert ähnlich wie die Funktion indexOf () in Java, die das erste Auftreten einer Eingabezeichenfolge zurückgibt.

Diese Lösung finden Sie hier http://www.linuxquestions.org/questions/linux-newbie-8/bash-string-manipulation-help-670627/ (letzter Beitrag). Dieser Typ hat mir den Tag gerettet. Gutschrift an ihn.

Schneller, wenn Sie Teilzeichenfolgen ab dem ersten Index ausführen möchten.

$ a = "eine lange Zeichenfolge"
$ b = "ri"
$ echo $ {a / * $ b / $ b}
Ring
$ echo $ {a / $ b * / $ b}
eine lange Zeichenfolge

/programming/10349102/shell-script-substring-from-first-indexof-substring

Linh Lino
quelle
0

Wenn Coreutils verfügbar sind, können Sie dies folgendermaßen tun:

echo $ {str / Age //} | cut -d / -f1 | wc -w

Per MariusMatutiae-Anfrage füge ich eine Erklärung hinzu, wie diese 3-Schritte-Operation funktioniert:

echo $ {str / Age //} 1. Ersetze den String, der nach einem eindeutigen Zeichen durchsucht wird (in meinem Fall /)

cut -d / -f1 2. schneide den ganzen Teil der Zeichenfolge ab, der nach einem eindeutigen Zeichen steht

wc -w 3. Zähle und drucke die verbleibenden Wörter. Dies gibt uns eine Indexnummer

Für Referenzen überprüfen Sie bitte:

http://www.tldp.org/LDP/abs/html/parameter-substitution.html (siehe: "Variable Erweiterung / Austausch von Teilzeichenfolgen")
http://www.gnu.org/software/coreutils/manual/coreutils .html (gehe zu: "Der Befehl cut" und "wc invocation"

PiotrO
quelle
Während dies das vorliegende Problem löst, werden solche knappen Antworten an diesen Stellen verpönt. Es wäre hilfreicher, ein paar Worte zu verwenden, um genau zu erklären, warum dies funktioniert. Bitte tun Sie dies.
Marius Matutiae
0

Eine Mischung aus zwei zuvor gegebenen Antworten unter Verwendung von reinen Bash-Arrays und Teilstring-Ersatz.

Die Idee ist, eine Zeichenfolge aller Wörter vor dem gewünschten zu erhalten und dann die Anzahl der Wörter in dieser Teilzeichenfolge zu zählen, indem Sie sie zu einem Array machen.

$ haystack="Name   Age Sex  ID         Address"
$ words_before=( ${haystack%Age*} )     # truncate string, make array
$ echo ${#words_before[*]}              # count words in array
1

Natürlich kann Age in einer anderen Variablen gespeichert needleund dann verwendet werden ${haystack%$needle*}. Erwarten Sie Probleme, wenn das gesuchte Wort eine Teilmenge eines anderen Wortes ist. In diesem Fall funktioniert die Antwort von kopischke immer noch.

Cimbali
quelle