Come trovare l'indice di una parola in una stringa in bash?


10

In bash script,

Ho una stringa che contiene diverse parole separate da uno o più spazi. vale a dire:

Name   Age Sex  ID         Address

Se voglio trovare una delle parole, ad esempio voglio trovare l'indice della parola "Età", come posso farlo?

Esiste un comando che restituirà direttamente il numero indice della parola che desidero?

Grazie.


La soluzione deve essere rigorosamente in bash? Oppure si può usare awk, grep, ecc.?
jftuga,

Risposte:


12

Bash esegue la suddivisione delle parole nelle stringhe da solo - in realtà, il più delle volte, evitando che ciò sia un problema e il motivo per cui la citazione è così importante. Nel tuo caso è facile sfruttarlo: basta inserire la stringa in un array senza citarla - bash utilizzerà la suddivisione delle parole per separare i singoli elementi. Supponendo che la stringa sia memorizzata nella variabile $str,

ar=($str) # no quotes!

restituirà una matrice di 5 elementi. Il tuo indice di array è il tuo indice di parole (contando da 0, come nella maggior parte dei linguaggi di scripting e di programmazione), vale a dire che "Age" è accessibile usando

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

oppure, se è necessario trovare l'indice degli elementi in base al contenuto, passare in rassegna l'array, ad es

function el_index {
    cnt=0; for el in "${ar[@]}"; do
        [[ $el == "$1" ]] && echo $cnt && break
        ((++cnt))
    done
}
el_index "Age" # => 1

wow ... non sapevo che senza le virgolette sarebbe stato un array. Grazie!
G3Y,

4
$ export FOO="Name   Age Sex  ID         Address"

Sostituisci * Age with Age: questo rimuoverà qualsiasi cosa prima di "Age":

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

Ottieni qualcosa prima di "Età"

$ echo ${FOO/Age*/}
Name

Ottieni la lunghezza di quella stringa (che è l'indice di "Età"):

$ BEGIN=${FOO/Age*/}
$ echo ${#BEGIN}
7

Non risponde alla domanda, ma wow! Slick trick. Funziona anche in cenere e con variabili incorporate: export L='debug info warn error'; export GTE='warn'; echo ${L/*${GTE}/${GTE}}stampa "avvisa errore"
Steve Tarver,

0

Se non devi usare rigorosamente bash, ma puoi usare altri programmi che si trovano comunemente sui sistemi con bash, allora potresti usare qualcosa del genere:

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

Python inizia a indicizzare la stringa da zero, quindi ho aggiunto +1 alla fine del comando.


0

Puoi usare la regex nativa di bash

# 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

Produzione

  2 Name
  9 Age
 13 Sex
 20 ID
 29 Address

0

Nota : supponendo qui che per indice intendiate sapere quale parola è (a partire da 0), non quale carattere nella stringa inizia la parola. Altre risposte riguardano quest'ultima.

Non che ne sia consapevole, ma puoi crearne uno. Due trucchi:

  1. Usa le abilità innate del costrutto for per dividere un input non quotato per spazi bianchi.
  2. Gestisci il caso in cui non riesci a trovare la colonna desiderata. In questo caso, ho scelto di inviare l'indice trovato a stout e lasciare che il codice di stato indichi se la ricerca è andata a buon fine. Ci sono altre possibilità

Codice:

#!/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

0

Prova il seguente oneliner javascript in una shell (usa la shell javascript):

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

O con un qui-doc:

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

0

Ho trovato una soluzione che funziona bene.

$ string = 'now is the time'
$ buf = the $ {string # * the}
$ echo $ buf
output: il tempo
$ index = $ (($ {# string} - $ {# buf} + 1))
$ echo $ indice
output: 8 -> indice della prima parola "the"

Funziona in modo simile alla funzione indexOf () in Java che restituisce la prima occorrenza di una stringa di input.

Ho trovato questa soluzione qui http://www.linuxquestions.org/questions/linux-newbie-8/bash-string-manipulation-help-670627/ (ultimo post). Questo ragazzo mi ha salvato la giornata. Ringraziamo lui.

Modo più veloce se si desidera eseguire la sottostringa dal primo indice di.

$ a = "some long string"
$ b = "ri"
$ echo $ {a / * $ b / $ b}
ring
$ echo $ {a / $ b * / $ b}
qualche lungo stri

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


0

Se sono disponibili coreutils puoi farlo nel modo seguente:

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

Per richiesta di MariusMatutiae sto aggiungendo una spiegazione su come funziona questa operazione in 3 passaggi:

echo $ {str / Age //} 1. Sostituisci la stringa alla quale si sta cercando un carattere univoco (nel mio caso /)

cut -d / -f1 2. taglia tutta la parte di stringa che segue un carattere univoco

wc -w 3. conta e stampa le parole rimaste che ci forniranno un numero indice

Per riferimenti consultare:

http://www.tldp.org/LDP/abs/html/parameter-substitution.html (vai a: "Espansione variabile / Sostituzione sottostringa")
http://www.gnu.org/software/coreutils/manual/coreutils .html (vai a: "Il comando cut" e "invocazione wc"


Mentre questo risolve il problema attuale, tali risposte concise sono disapprovate in questi siti. Sarebbe più utile spendere qualche parola spiegando esattamente perché questo funziona. Per favore fallo.
MariusMatutiae,

0

Un mix di due risposte precedentemente fornite, usando array di bash puri e sostituzione di sottostringa.

L'idea è quella di ottenere una stringa di tutte le parole prima di quella desiderata, quindi contare il numero di parole in quella sottostringa trasformandola in un array.

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

Naturalmente Age può essere memorizzato in un'altra variabile needle, quindi utilizzare ${haystack%$needle*}. Aspettati dei problemi se la parola che cerchi è un sottoinsieme di un'altra parola, nel qual caso la risposta di kopischke funziona ancora.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.