8

В bash-скрипте

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

Name   Age Sex  ID         Address

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

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

Благодарю.

9 ответов9

10

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
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
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*} . Ожидайте проблем, если искомое слово является подмножеством другого слова, и в этом случае ответ Копишке все еще работает.

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

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

echo $ {str/Age//} | вырезать -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").

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

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

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

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

0

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

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

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

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

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

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

https://stackoverflow.com/questions/10349102/shell-script-substring-from-first-indexof-substring

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .