Як знайти індекс слова в рядку в bash?


10

У сценарії bash,

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

Name   Age Sex  ID         Address

Якщо я хочу знайти будь-яке слово, наприклад, я хочу знайти індекс слова "Вік", як це зробити?

Чи є якась команда, яка поверне індексний номер слова, який я хочу безпосередньо?

Дякую.


Чи має рішення бути суворо башком? Або можна використовувати 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 на вік - це видалить що завгодно до "Age":

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

Отримайте що-небудь перед "Віком"

$ echo ${FOO/Age*/}
Name

Отримайте довжину цього рядка (який є індексом "Вік"):

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

Не відповідає на питання, але вау! Витончена хитрість. Він працює навіть у золі та із вбудованими змінними: export L='debug info warn error'; export GTE='warn'; echo ${L/*${GTE}/${GTE}}друкує "попереджати про помилку"
Стів Тарвер

0

Якщо вам не потрібно суворо використовувати bash, але ви можете використовувати інші програми, які часто зустрічаються в системах з bash, ви можете використовувати щось подібне:

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

Python починає строкову індексацію з нуля, тому я додав +1 до кінця команди.


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

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

Спробуйте наступний JavaScript oneliner в оболонці (використовуйте оболонку 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 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}
деяка довга смуга

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


0

Якщо Coreutils доступні, ви можете зробити це наступним чином:

echo $ {str / Age //} | вирізати -d / -f1 | wc -w

На запит MariusMatutiae я додаю пояснення, як працює ця 3-х крокова операція:

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"


Хоча це вирішує проблему, на такі сайти нахмурені такі лайливі відповіді. Було б корисніше витратити кілька слів, пояснюючи, чому саме це працює. Будь ласка, зробіть це.
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*}. Очікуйте проблем, якщо шукане слово є підмножиною іншого слова, і в цьому випадку відповідь kopischke все ще працює.


0

Це запитання для 7 років, але на деякі, можливо, знадобиться відповідь у чистому душі.

STRING="Name   Age Sex  ID         Address"
INDEXOF_AGE=${#${STRING/Age*/}}
echo $INDEXOF_AGE
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.