Como encontrar o índice de uma palavra em uma string no bash?

10

No script bash,

Eu tenho uma string que contém várias palavras separadas por um ou mais de um espaço. ou seja:

Name   Age Sex  ID         Address

Se eu quiser encontrar alguma palavra, por exemplo, quero encontrar o índice da palavra "Idade", como posso fazer isso?

Existe algum comando que retornará o número de índice da palavra que eu quero diretamente?

Obrigado.

G3Y
fonte
A solução precisa estar estritamente no bash? Ou pode ser usado o awk, grep, etc.?
jftuga
Post relacionado: Como imprimir determinadas colunas pelo nome?
zx8754 18/07/19

Respostas:

12

O Bash realiza a divisão de palavras em strings por si só - na verdade, mais frequentemente do que não, evitando que isso seja um problema, e a razão pela qual a citação é tão importante. É fácil aproveitar isso no seu caso: basta colocar sua string em uma matriz sem citá-la - o bash usará a divisão de palavras para separar os elementos individuais. Assumindo que o seu string é armazenado na variável $str,

ar=($str) # no quotes!

retornará uma matriz de 5 elementos. Seu índice de matriz é o seu índice de palavras (contando desde 0, como na maioria das linguagens de script e de programação), ou seja, "Idade" é acessada usando

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

ou, se você precisar encontrar o índice do elemento por conteúdo, faça um loop sobre a matriz, ou seja,

function el_index {
    cnt=0; for el in "${ar[@]}"; do
        [[ $el == "$1" ]] && echo $cnt && break
        ((++cnt))
    done
}
el_index "Age" # => 1
kopischke
fonte
uau ... eu não sabia que sem as aspas, então seria uma matriz. obrigado!
G3Y
4
$ export FOO="Name   Age Sex  ID         Address"

Substitua * Idade por Idade - isso removerá qualquer coisa antes de "Idade":

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

Consiga qualquer coisa antes de "Idade"

$ echo ${FOO/Age*/}
Name

Obtenha o comprimento dessa string (que é o índice de "Age"):

$ BEGIN=${FOO/Age*/}
$ echo ${#BEGIN}
7
user1034081
fonte
Não responde a pergunta, mas uau! Truque liso. Até funciona no ash e com variáveis ​​incorporadas: export L='debug info warn error'; export GTE='warn'; echo ${L/*${GTE}/${GTE}}impressões 'alertam erros'
Steve Tarver
0

Se você não precisar usar estritamente o bash, mas puder usar outros programas comumente encontrados em sistemas com o bash, poderá usar algo como isto:

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

Python inicia sua indexação de string em zero, portanto adicionei +1 ao final do comando.

jftuga
fonte
0

Você pode usar o regex nativo do 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

Resultado

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

Nota : Assumindo aqui que, por índice, você quer saber qual palavra é (a partir de 0), e não em qual caractere na sequência a palavra começa. Outras respostas abordam o último.

Não que eu saiba, mas você pode fazer um. Dois truques:

  1. Use as habilidades inatas da construção for para dividir uma entrada não citada pelo espaço em branco.
  2. Lide com o caso em que você não consegue encontrar a coluna desejada. Nesse caso, escolhi enviar o índice encontrado para stout e deixar o código de status indicar se a descoberta foi bem-sucedida. Existem outras possibilidades.

Código:

#!/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.
fonte
0

Experimente o seguinte javascript oneliner em um shell (use javascript shell):

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

Ou com um documento aqui:

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

Encontrei uma solução que funciona bem.

$ string = 'agora é a hora'
$ buf = a saída $ {string # * the}
$ echo $ buf
: a hora
$ index = $ (($ {# string} - $ {# buf} + 1))
$ eco $ index
output: 8 -> índice da primeira palavra "the"

Funciona de maneira semelhante à função indexOf () em Java, que retorna a primeira ocorrência de uma sequência de entrada.

Encontre esta solução aqui http://www.linuxquestions.org/questions/linux-newbie-8/bash-string-manipulation-help-670627/ (última postagem). Esse cara salvou o meu dia. Crédito para ele.

Maneira mais rápida se você deseja fazer substring a partir do primeiro indexof.

$ a = "alguma string longa"
$ b = "ri"
$ echo $ {a / * $ b / $ b}
toque
$ echo $ {a / $ b * / $ b}
alguma stri longa

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

Linh Lino
fonte
0

Se o coreutils estiver disponível, você poderá fazê-lo da seguinte maneira:

eco $ {str / Age //} | corte -d / -f1 | wc -w

Por solicitação MariusMatutiae, estou adicionando uma explicação de como esta operação de 3 etapas funciona:

echo $ {str / Age //} 1. substitua a string que está sendo pesquisada por um caractere único (no meu caso /)

cut -d / -f1 2. corta toda a parte da corda que está atrás do caractere único

wc -w 3. conte e imprima as palavras restantes, isso nos dará um número de índice

Para referências, verifique:

http://www.tldp.org/LDP/abs/html/parameter-substitution.html (acesse: "Expansão variável / substituição de substring")
http://www.gnu.org/software/coreutils/manual/coreutils .html (acesse: "O comando recortar" e "invocação wc"

PiotrO
fonte
Enquanto isso resolve o problema em questão, essas respostas concisas são desaprovadas nesses sites. Seria mais útil passar algumas palavras explicando exatamente por que isso funciona. Por favor, faça isso.
MariusMatutiae
0

Uma mistura de duas respostas fornecidas anteriormente, usando matrizes de bash puras e substituição de substring.

A idéia é obter uma sequência de todas as palavras antes da que você deseja e, em seguida, conte o número de palavras nessa substring, transformando-a em uma matriz.

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

É claro que o Age pode ser armazenado em outra variável needlee depois usar ${haystack%$needle*}. Espere problemas se a palavra que você procurar for um subconjunto de outra palavra, caso em que a resposta do kopischke ainda está funcionando.

Cimbali
fonte