Как найти индекс слова в строке в bash?

10

В скрипте bash,

У меня есть строка, которая содержит несколько слов, разделенных одним или несколькими пробелами. то есть:

Name   Age Sex  ID         Address

Если я хочу найти какое-либо слово, например, я хочу найти индекс слова «Возраст», как я могу это сделать?

Есть ли какая-нибудь команда, которая будет возвращать порядковый номер слова, которое я хочу напрямую?

Спасибо.

G3Y
источник
Решение должно быть строго в bash? Или можно использовать awk, grep и т. Д.?
Jftuga

Ответы:

12

Bash выполняет разбиение слов по строкам само по себе - на самом деле, чаще всего, избегая этой проблемы, а цитирование причины так важно. Это легко использовать в вашем случае: просто поместите вашу строку в массив без кавычек - bash будет использовать разбиение слов для разделения отдельных элементов. Предполагая, что ваша строка хранится в переменной $str,

ar=($str) # no quotes!

вернет массив из 5 элементов. Индекс вашего массива - это индекс вашего слова (считая от 0, как в большинстве языков сценариев и программирования), т.е. к «Возрасту» обращаются с помощью

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

или, если вам нужно найти индекс элемента по содержимому, выполните цикл по массиву, т.е.

function el_index {
    cnt=0; for el in "${ar[@]}"; do
        [[ $el == "$1" ]] && echo $cnt && break
        ((++cnt))
    done
}
el_index "Age" # => 1
Копишке
источник
вау ... я не знал, что без кавычек тогда это будет массив. Спасибо!
G3Y
4
$ export FOO="Name   Age Sex  ID         Address"

Замените * Age with Age - это удалит что-либо до "Age":

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

Получите что-нибудь до "возраста"

$ echo ${FOO/Age*/}
Name

Получите длину этой строки (которая является индексом «возраста»):

$ BEGIN=${FOO/Age*/}
$ echo ${#BEGIN}
7
user1034081
источник
Не отвечает на вопрос, но вау! Ловкий трюк Он работает даже в золе и со встроенными переменными: export L='debug info warn error'; export GTE='warn'; echo ${L/*${GTE}/${GTE}}выводит сообщение «error error»
Стив Тарвер,
0

Если вам не нужно строго использовать bash, но вы можете использовать другие программы, обычно встречающиеся в системах с bash, тогда вы можете использовать что-то вроде этого:

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

Python начинает индексирование строк с нуля, поэтому я добавил +1 в конец команды.

jftuga
источник
0

Вы можете использовать родное регулярное выражение 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

Вывод

  2 Name
  9 Age
 13 Sex
 20 ID
 29 Address
Peter.O
источник
0

Примечание . Предполагается, что здесь под индексом подразумевается, что вы хотите знать, какое это слово (начиная с 0), а не какой символ в строке начинается с этого слова. Другие ответы касаются последнего.

Не то, чтобы я знал, но вы можете сделать один. Два трюка:

  1. Используйте врождённые способности для конструкции дробить в кавычках ввода пробелов.
  2. Обработайте случай, когда вы не можете найти нужную колонку. В этом случае я решил отправить найденный индекс в stout и позволить коду состояния указывать, была ли находка успешной. Есть и другие возможности.

Код:

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

Попробуйте следующий oneliner javascript в оболочке (используйте оболочку javascript):

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

Или с документом здесь:

js <<EOF
x = 'Name   Age Sex  ID         Address';
print(x.indexOf('Age'));
EOF
Жиль Квено
источник
0

Я нашел решение, которое отлично работает.

$ string = 'сейчас время'
$ buf = вывод $ {string # * the}
$ echo $ buf
: время
$ index = $ (($ {# string} - $ {# buf} + 1))
$ echo $ index
output: 8 -> index первого слова "the"

Он работает аналогично функции indexOf () в Java, которая возвращает первое вхождение входной строки.

Нашел это решение здесь http://www.linuxquestions.org/questions/linux-newbie-8/bash-string-manipulation-help-670627/ (последнее сообщение). Этот парень спас мой день. Отдайте ему.

Более быстрый способ, если вы хотите сделать подстроку из первого indexof.

$ a = "какая-то длинная строка"
$ b = "ri"
$ echo $ {a / * $ b / $ b}
ring
$ echo $ {a / $ b * / $ b}
некоторая длинная полоса

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

Линь Лино
источник
0

Если доступны coreutils, вы можете сделать это следующим образом:

echo $ {str / Age //} | cut -d / -f1 | туалет

В соответствии с запросом MariusMatutiae я добавляю объяснение, как работает эта трехэтапная операция:

echo $ {str / Age //} 1. заменить строку, в которой ищется уникальный символ (в моем случае /)

cut -d / -f1 2. отрезать целую часть строки после уникального символа

wc -w 3. подсчитать и напечатать слова, которые остались, это даст нам порядковый номер

Для ссылок, пожалуйста, проверьте:

http://www.tldp.org/LDP/abs/html/parameter-substitution.html (см. «Расширение переменной / замена подстроки»)
http://www.gnu.org/software/coreutils/manual/coreutils .html (перейти к: «Команда вырезания» и «вызов wc»

PiotrO
источник
Хотя это решает проблему, такие краткие ответы не одобряются на этих сайтах. Было бы более полезно потратить несколько слов, объясняющих, почему это работает. Пожалуйста, сделай так.
MariusMatutiae
0

Сочетание двух ранее заданных ответов с использованием чистых массивов bash и замены подстрок.

Идея состоит в том, чтобы получить строку всех слов перед тем, которое вы хотите, а затем подсчитать количество слов в этой подстроке, превратив ее в массив.

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

Конечно, возраст можно сохранить в другой переменной needle, а затем использовать ${haystack%$needle*}. Ожидайте проблем, если искомое слово является подмножеством другого слова, и в этом случае ответ Копишке все еще работает.

Cimbali
источник
0

Это 7-летний вопрос, но некоторые могут нуждаться в ответе в чистом виде.

STRING="Name   Age Sex  ID         Address"
INDEXOF_AGE=${#${STRING/Age*/}}
echo $INDEXOF_AGE
Генри Чен
источник