2016-12-30 3 views
2

それを更新します。ランダムIは、配列の項目の数を選択し、最後のセットまで再びそれを行うには、それを更新し、ランダムにしようとしています配列からN項目を選択し、BASHスクリプト内

#! /bin/bash 

A=({1..27}) 
T=${#A[@]} #number of items in the array 
N=3 #number of items to be chosen 
V=$(($T/$N)) #number of times to loop 
echo ${A[@]} " >> ${#A[@]}" 
for ((n=0;n<$V;n++)); do 
    A1=() 
    for I in `shuf --input-range=0-$((${#A[*]} - 1)) | head -${N}`; do #random chooses N items random 
     S=`echo ${A[$I]}` #the chosen items 
     #echo $S 
     A1+=("$S|") #creates an array with the chosen items 
     A=("${A[@]/$S}") #deletes the the chosen items from array 
    done 
    echo ${A[@]} " >> ${#A[@]}" 
    echo ${A1[@]} " >> ${#A1[@]}" 
done 

タイプ私がこのコードを取得している出力の:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 >> 27 
1 4 5 6 7 8 9 10 11 1 1 14 15 16 17 18 19 1 2 4 5 6 7 >> 27 
20| 2| 3| >> 3 
4 6 7 8 9 0 1 4 6 7 8 9 2 4 6 7 >> 27 
1| | 5| >> 3 
6 7 8 9 0 1 6 7 8 9 2 6 7 >> 27 
| | 4| >> 3 
7 8 9 0 1 7 8 9 2 7 >> 27 
6| | | >> 3 
7 8 9 0 1 7 8 9 7 >> 27 
| | 2| >> 3 
7 9 0 1 7 9 7 >> 27 
8| | | >> 3 
7 9 1 7 9 7 >> 27 
| | 0| >> 3 
7 9 1 7 9 7 >> 27 
| | | >> 3 
1 >> 27 
9| 7| | >> 3 

なぜそれが最初に正常に動作し、最後に失敗するか?

+1

将来は '#!/ bin // bash'行の後に' set -x'を使って、デバッガモードでスクリプトを実行してください。私は、 'A =({1..5}) 'という最小限の入力を維持することによって、配列Aからの不適切な削除を根本原因にしました。 – Inian

+1

また、コマンド出力の処理に 'for-loop'を使用せず、適切に' IFS'を使用して、プロセス置換で 'while-loop'を使用してください。 – Inian

答えて

1

スクリプトに作ることができるいくつかの改善があります。

  1. 利用小文字
  2. は("${a[@]}")あなたの拡大を引用します。
  3. unset a[j]を実行してアイテムを削除します。
  4. a=("${a[@]}")でアレイを再構築します。
  5. shufが-nでカウント結果を生成できるため、頭の必要はありません。
  6. 代わりに逆引用符を使用しないでください。$(…)を代わりに使用してください。これは、この出力を生成します

    #!/bin/bash 
    
    t=27    #number of items in the array 
    n=3     #number of items to be chosen 
    a=($(seq 1 "$t")) 
    a1=() 
    
    while ((${#a[@]} >= n)); do 
        for j in $(shuf -n "$n" --input-range=0-$((${#a[@]}-1))); do # choose $n random items. 
         a1+=("${a[j]}")  # append to an array the chosen items. 
         unset "a[j]"   # deletes the the chosen items from array. 
        done 
        a=("${a[@]}")    # re-build the array. 
        echo "a ${a[@]} >> ${#a[@]}" 
        echo "a1 ${a1[@]} >> ${#a1[@]}" 
    done 
    

    a 1 2 3 5 6 7 8 9 10 11 12 14 15 16 18 19 20 21 22 23 24 25 26 27 >> 24 
    a1 17 13 4 >> 3 
    a 1 2 5 6 7 8 10 11 12 14 15 16 18 19 20 21 22 23 24 26 27 >> 21 
    a1 17 13 4 25 3 9 >> 6 
    a 1 2 5 6 7 8 10 11 14 15 16 18 21 22 23 24 26 27 >> 18 
    a1 17 13 4 25 3 9 12 20 19 >> 9 
    a 1 2 5 7 8 10 11 14 15 16 21 22 24 26 27 >> 15 
    a1 17 13 4 25 3 9 12 20 19 23 6 18 >> 12 
    a 2 7 8 10 11 14 15 16 22 24 26 27 >> 12 
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 >> 15 
    a 2 8 10 14 15 22 24 26 27 >> 9 
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 >> 18 
    a 2 10 14 24 26 27 >> 6 
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 >> 21 
    a 14 26 27 >> 3 
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 2 24 10 >> 24 
    a >> 0 
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 2 24 10 14 26 27 >> 27 
    

    しかし、同じ配列a1はちょうどSHUFと1つのステップで構築することができます

    にスクリプトを軽減します

次のようになります。

$ ./script.sh 
15 23 1 9 24 2 21 11 12 10 19 25 27 13 5 26 4 7 14 3 22 20 17 18 16 6 8 

あるいは、結果は行ごとに$n要素にする必要がある場合:

#!/bin/bash 

t=27         # number of items in the array 
n=3          # number of items to be chosen 
a1=($(shuf --input-range=1-"$t")) 

while ((i+n<=t)); do 
    printf '%3s ' "${a1[@]:i:n}"; echo 
    ((i+=n)) 
done 

印刷:

$ ./script.sh 
    7 19 16 
    4 20 26 
11 23 2 
13 6 15 
22 12 25 
18 14 10 
21 8 9 
    5 24 27 
    1 3 17 

は簡単な解決策のように見えます。

+0

非常に洞察力のあるヒント、ありがとう。 – Roger

1

あなたのスクリプトにはいくつか間違ったことがあります。特に、あなたが考えている方法では、配列から要素を削除する方法があります。要素を削除するわけではありません。すべてのフィールドで値を空の文字列に置き換えるだけです!。だからあなたの配列には27個の要素があり、最初の反復の後にはすべて23がすべてのフィールドから削除されています。ここではより多くの慣用的なスクリプトがあります:

#! /bin/bash 

a=({1..27}) 
n=3 #number of items to be chosen 
while ((${#a[@]}>=n)); do 
    a1=() 
    for ((i=0;i<n;++i)); do 
     # pick an index 
     x=$((RANDOM%${#a[@]})) 
     # append its value to array a1 
     a1+=("${a[x]}") 
     # unset it 
     unset 'a[x]' 
     # reconstruct array a (make it non-sparse again) 
     a=("${a[@]}") 
    done 
    # print array 
    printf 'a: %s >> %s\n' "${a[*]}" "${#a[@]}" 
    # print chosen elements 
    printf 'a1: %s >> %s\n' "${a1[*]}" "${#a1[@]}" 
done 
+0

このスクリプトにはいくつか間違った考えがあります。一つ:乱数xが一様に分布していない。変数RANDOMは、0〜32767の範囲の整数を生成します。各32768の描画では、平均でRANDOM%100は、範囲68-99の範囲で0-67と327の範囲で328の結果を生成します。それは明らかに不均一なランダム分布です。 – sorontar

+0

xの値は単純なループで均一にすることができます: 'range = 27; a = $ RANDOM; until((a <(32767/range)* range)); a = $ RANDOMを実行します。完了しました。 echo "a = $ a x = $((%範囲))" 'しかし、なぜshufは簡単な呼び出しで同じことをすることができるのでしょうか? 'x = $(shuf -i 0-27 -n 1)'。 – sorontar

+0

もちろん、RANDOMとshufはどちらも単純なランダムな要求に対応しています。 CSPRNGが必要な場合は、「多分単純」(http://security.stackexchange.com/a/44377/126077) 'printf '%d \ n」「0x $(openssl rand -hex 4)」'(32 'printf '%d \ n'" 0x $(/ dev/urandom bs = 1 count = 4 2>/dev/nullの場合はddとなります) | xxd -p) "'(やはり32ビットの10進数)。 – sorontar

関連する問題