2

私はプロジェクトに苦労しています。tr コマンドのように機能する bash スクリプトを作成することになっています。最初に、すべてのコマンド引数を別々の配列に保存したいと思います。また、引数が単語の場合、各文字を区切られた配列フィールドに入れたいと思います。

tr_mine AB DC 

a[0] = A、a[1] = B、b[0]=C b[1]=D の 2 つの配列が必要です。

私は方法を見つけましたが、うまくいきません:

IFS="" read -r -a array <<< "$a"
4

3 に答える 3

2

sed も awk もありません。すべて bash の内部構造です。

単語は常に空白 (スペースおよび/またはタブ) で区切られていると
仮定し、単語が引数として与えられると仮定し、bash のみを記述します。

#!/bin/bash

blank=$'[ \t]'
varname='A'

n=1
while IFS='' read -r -d '' -N 1 c ; do
    if [[ $c =~ $blank ]]; then n=$((n+1)); continue; fi
    eval ${varname}${n}'+=("'"$c"'")'
done <<<"$@"

last=$(eval echo \${#${varname}${n}[@]})        ### Find last character index.
unset "${varname}${n}[$last-1]"                 ### Remove last (trailing) newline.

for ((j=1;j<=$n;j++)); do
    k="A$j[@]"
    printf '<%s> ' "${!k}"; echo
done

これにより、各配列 A1、A2、A3 などが設定されます ... 各単語の文字に。

の最初のループの最後の値は、$n処理された単語の数です。印刷は少し難しいかもしれません。そのため、各文字にアクセスするためのコードが上に示されています。

サンプル テキストに適用:

$ script.sh AB DC 
<A> <B>
<D> <C>

スクリプトは 2 つの (配列) varsA1と を設定してA2います。
そして、各文字は 1 つの配列要素です: A1[0] = A、A1[1] = B、および A2[0]=C、A2[1]=D。

$kアクセスする配列要素に変数( )を設定する必要があります。
たとえば、echo2 番目の単語 (1 ベース) の 4 文字目 (0 ベース) に対しては、次のことを行う必要があります (必要に応じて変更される可能性があります)。

k="A2[3]"; echo "${!k}"            ### Indirect addressing.

スクリプトは次のように機能します。

$ script.sh ABCD efghi
<A> <B> <C> <D> 
<e> <f> <g> <h> <i> 

注意:引用しても文字が分割されます。ただし、引用符で囲まれた引数は、このスクリプトを使用してシェルのメタ文字 ( |,&,;,(,),<,>,space,tab ) の影響を回避する正しい方法です。もちろん、スペースは (たとえ繰り返されたとしても) 変数で定義されたように単語を分割します$blank:

$ script.sh $'qwer;rttt    fgf\ngfg'
<q> <w> <e> <r> <;> <r> <t> <t> <t> 
<> 
<> 
<> 
<f> <g> <f> <
> <g> <f> <g>

スクリプトは埋め込み改行を受け入れて正しく処理するため、使用する必要があるunset "${varname}${n}[$last-1]"のは、最後の末尾の「改行」を削除することです。それが望ましくない場合は、その行を引用してください。

セキュリティに関する注意: eval は一度に1文字しか処理しないため、ここではあまり問題になりません。一人のキャラクターだけで攻撃を作るのは難しいでしょう。とにかく、通常の警告は有効です: このスクリプトを使用する前に、常に入力をサニタイズしてください。また、bash のほとんどの (引用されていない) メタ文字は、このスクリプトを壊します。

$ script.sh qwer(rttt    fgfgfg
bash: syntax error near unexpected token `('
于 2016-04-03T23:02:52.860 に答える
0

可能であれば、これを別の言語で行うことを強くお勧めします。はるかに簡単です。

今、私が思いついた最も近いものは次のとおりです。

#!/bin/bash

sentence="AC DC"
words=`echo "$sentence" | tr " " "\n"`

# final array
declare -A result

# word count
wc=0

for i in $words; do
    # letter count in the word
    lc=0
    for l in `echo "$i" | grep -o .`; do
        result["w$wc-l$lc"]=$l
        lc=$(($lc+1))

    done
    wc=$(($wc+1))
done

rLen=${#result[@]}
echo "Result Length $rLen"


for i in "${!result[@]}"
do
  echo "$i => ${result[$i]}"
done

上記のプリント:

Result Length 4
w1-l1 => C
w1-l0 => D
w0-l0 => A
w0-l1 => C

説明:

  • 動的変数は bash ではサポートされていない (つまり、変数を使用して変数を作成する) ため、代わりに連想配列を使用しています ( result)
  • bash の配列は 1 次元です。2D 配列を偽造するには、w単語とl文字のインデックスを使用します。これにより、さらに処理が面倒になります...
  • 連想配列は順序付けされていないため、印刷時に結果がランダムな順序で表示されます
  • ${!result[@]}の代わりに使用されます${result[@]}。1 つ目はキーを反復し、2 つ目は値を反復します

これがまさにあなたが求めているものではないことはわかっていますが、正しい方向に向けられることを願っています

于 2016-04-03T09:11:03.837 に答える