bashで文字列内の単語のインデックスを見つける方法は?


10

bashスクリプトでは、

1つ以上のスペースで区切られた複数の単語を含む文字列があります。つまり:

Name   Age Sex  ID         Address

「Age」という単語のインデックスを検索するなど、単語を検索したい場合はどうすればよいですか?

必要な単語のインデックス番号を直接返すコマンドはありますか?

ありがとう。


ソリューションは厳密に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をAgeに置き換えます。これにより、「Age」の前のものがすべて削除されます。

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

「年齢」より前に入手する

$ echo ${FOO/Age*/}
Name

その文字列の長さ( "Age"のインデックス)を取得します。

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

質問には答えませんが、すごい!スリックトリック。ashでも、埋め込み変数でも機能します:export L='debug info warn error'; export GTE='warn'; echo ${L/*${GTE}/${GTE}}「警告エラー」を出力します
Steve Tarver

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から始まる)どの単語であるかを知りたいと想定していることを前提としています。他の答えは後者に対処します。

私が知っていることではありませんが、あなたはそれを作ることができます。2つのトリック:

  1. for構造の固有の機能を使用して、引用符で囲まれていない入力を空白で分割します。
  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 shellを使用)。

$ 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 = 'now is the time'
$ buf = the $ {string#* the}
$ echo $ buf
output:the time
$ index = $(($ {#string}-$ {#buf} + 1))
$ echo $ index
output:8->最初の単語「the」のインデックス

これは、入力文字列の最初のオカレンスを返すJavaの関数indexOf()と同様に機能します。

このソリューションは、http://www.linuxquestions.org/questions/linux-newbie-8/bash-string-manipulation-help-670627/(最後の投稿)で見つかりました。この男は私の日を救った。彼の功績です。

最初のindexofから部分文字列を作成する場合は、より高速な方法。

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

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


0

coreutilsが利用可能な場合は、次の方法で実行できます。

エコー$ {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 2014

0

純粋なbash配列と部分文字列置換を使用した、以前に与えられた2つの答えの組み合わせ。

アイデアは、必要な単語の前にすべての単語の文字列を取得し、それを配列にして、その部分文字列の単語数を数えることです。

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

もちろん、Ageを別の変数needleに格納してから使用できます${haystack%$needle*}。検索する単語が別の単語のサブセットである場合、問題が発生する可能性があります。その場合、コピッシュケの回答は引き続き機能します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.