空の配列要素を0に設定するには?

空の配列要素を0に設定するには?

コマンドの結果を出力配列に送信するスクリプトを作成しています。これには、サーバーのログを確認してそのサイズを取得する操作が含まれますが、場合によってはサーバーにフェールオーバーホストがあります。このような場合、両方のホストを確認して値を返すスクリプトが必要です。私が遭遇している問題は、出力配列要素の1つが空である場合(検査中のファイルがサーバーに存在せず、対応するエコーディスプレイに空白のみが返されることを意味する)、これは配列インデックスが変更されることです。これは、セカンダリホストアレイセットに存在する必要があるエントリがプライマリホストアレイセットに遭遇することを意味します。代わりに、移動が発生しないように、これらの空のインデックスをプレースホルダとしてゼロとして保存したいと思います。インデックスオフセットが明らかになる場所は次のとおりです。

echo The primary overall log value is ${output[0]}.
echo The primary obs log value is ${output[2]}.    
echo The primary tracks log value is ${output[4]}.  
echo
echo The secondary overall log value is ${output[6]}.
echo The secondary overall log value is ${output[8]}.
echo The secondary overall log value is ${output[10]}.

たとえば、出力[2]と[4]が空の場合、出力[6]は出力[2]に対応する行に上に移動します。この解決策を試しましたが、運がありません。

  s=0

  for x in "${output[@]}"
     do(
     x=
        if [[ -z $x ]];
        then(
        x=0
        echo $x)
        else echo
        fi
     s=s+1)
 done

これらのタスクはすべて、出力エコーが発生する前にゼロを吐き出し、インデックスの動きを調整しません。

注:出力配列のソースは次のとおりです。これを修正する試みは次のとおりです。

for h in "${host[@]}"
do
    for path in "${paths[@]}"
    do
            output+=( $(ssh $h du -sh $path) )
            for x in "${!output[@]}";
            do(
                    if [[ -z "${output[$x]}" ]];
                    then output[$x]=0;
                    fi;
            )
            done

    done
done

ホストとパスはすでに定義されている配列です。また、アクセス可能なホストが1つしかない場合は、スクリプトが正しく実行され、配列のインデックス付けに問題がないことも確認しました。

ベストアンサー1

たとえば、出力[2]と[4]が空の場合、出力[6]は出力[2]に対応する行に上に移動します。

この場合、実際には2と4をnull値に置き換えるのではなく、予想よりも少ない値になります。

配列の割り当てを検討してください。

array1=(a b c d)
array2=(A D)

最初は、〜などarray1[0]に設定されます。 2番目はとに設定されます。との間にNULL値が必要かどうかを知る方法はありません。課題に明示的に表示する必要があります。aarray1[1]barray2[0]Aarray2[1]DAD

array2=(A "" "" D)

他の方法で配列を埋めることもできますが、outputその方法を示していないため、これについて言及することはできません。上記のような状況が発生する可能性があります。 「空」の値は、配列を埋めるどの値でもまったく値とは見なされませんoutput

拡張が配列に割り当ててトークン化に依存している場合は、これを回避できません。 (新しい行だけが含まれていても、連続した空白行IFSを1つに縮小して空白行を削除します。)を使用する場合は、デフォルトでmapfile空白行を配列要素として表示する必要があります。


いずれの場合でも、空の配列要素をゼロにするループは、ループ内の配列にまったく割り当てられていないため機能しません。(...))、したがって、すべての割り当てはループ本体の外部では発生しません。

for x in "${output[@]}"実際、配列要素を効果的に変更するためにaを使用することはできません。x配列値のコピーのみを取得し、それを変更しても元の値は変更されないためです。配列を指すように配列インデックスを繰り返す必要があります。

somearray=(1 "" "" 4)
for i in "${!somearray[@]}"; do
    if [[ -z "${somearray[$i]}" ]]; then
        somearray[$i]=0;
    fi;
done
echo "${somearray[@]}"

印刷1 0 0 4


追加したサンプルコードでは、割り当ては空のoutput+=( $(ssh $h du -sh $path) )要素を追加しません。欠落しているパスは配列から省略されます。まず考えてみてください。du $path パスが存在しない場合は何も印刷されません。 (stderrに送信され、コマンド置換によってキャプチャされないエラーは除く。)また、空白行(またはスペース/タブ)を印刷しても、トークン化は連続したスペースを削除します。

たとえばarray=( $( printf "foo\n\nbar\n" ) )、2つの要素を持つ配列を作成します。

さらに、ループ内の括弧を置き換えるとサブシェルが開始されるため、配列に対する変更はそのサブシェル内でのみ適用されます。一般的に言えば、あなたはいいえ特にサブシェルが必要であることを知らない限り、括弧を使用してシェルコマンドをグループ化できます。

"$(ssh ... du)"正確な文字列を得るために、コマンドの置き換え()の周りに引用符を入れることができますが、パス名からサイズを区切ることもできます。

パスとサイズを単一の配列として収集するには、次のようにしてみてください。

for host in "${hosts[@]}"; do
    for path in "${paths[@]}"; do
        output="$(ssh "$host" du -sh "$path")"
        size="${output%%$'\t'*}"           # needs Bash/ksh/zsh
        size="${size:-0}"
        sizes+=( "$size" "$host:$path"  )
    done
done

各偶数配列要素にはサイズが含まれ、各奇数配列要素には、分割出力結果duとやや類似した対応するホスト名とパスが含まれます。両方の引数は、タブ文字の後のすべての項目を展開して削除し、空の場合はoutputサイズを0に置き換えます。size

または、以下をビルドできます。連想配列、ホスト+パスで索引付けされている:

declare -A array
...
    array["$host:$path"]=$size

おすすめ記事