
Bashの配列にはいくつかの問題があります。
A=( "127.0.0.1" "localhost" "aaa nnn cvcc" )
B=( "8.8.8.8" "dns" "bbb tttt rrrr")
for n in ${A} ${B} ; do
if ping -c3 ${n[0]};then
echo "${n[1]}"
for share in ${n[2]};do
echo $share
done
fi
done
配列の2番目と3番目の要素を印刷したいのですが、forループはpingで停止します。だから動作します。
if ping -c3 ${A[0]};then
echo "${A[1]}"
for share in ${A[2]};do
echo $share
done
fi
本当に愚かなことですが、本当に狂っていると思います...アイデアがありますか?事前にありがとう
答え1
A
ループは実際にはandの最初の要素であるandを繰り返しますB
。これは${A[0]}
、andがwhileと同じ空の文字列であることを${B[0]}
意味します。${n[1]}
${n[2]}
${n[0]}
$n
bash
バージョン4.3以降では、名前参照変数を使用してこれを実行できます。
#!/bin/bash
A=( 127.0.0.1 localhost alpha beta gamma theta )
B=( 8.8.8.8 dns itsy bitsy 'spider man' )
for variable in A B; do
declare -n array="$variable"
if ping -c3 "${array[0]}" >/dev/null; then
printf '%s\n' "${array[1]}"
printf '\t%s\n' "${array[@]:2}"
fi
done
変数を繰り返しています。名前 A
そしてB
、その内容よりは。ループ内でarray
という変数の名前参照を作成します$variable
。 Nowはorarray
でのみ使用されます。A
B
このif
説明では、ループの3番目の配列要素を分割するためにシェルを使用しません。代わりに、A
配列を作成するときにB
手動で分割し、配列printf
のオフセットを使用して単一の呼び出しを実行して要素を出力しますarray
。読みやすくするために、各要素の前にタブを出力しました。
localhost
alpha
beta
gamma
theta
dns
itsy
bitsy
spider man
このif
ステートメントは次のように書くこともできます。
if ping -c3 "${array[0]}" >/dev/null; then
printf '%s: ' "${array[1]}"
( IFS=,; printf '%s\n' "${array[*]:2}" )
fi
残りの配列要素をコロンの後にカンマ区切りのリストとして出力します。
localhost: alpha,beta,gamma,theta
dns: itsy,bitsy,spider man
注:上記の引用は偶然ではありません。参照配列を拡張すると、各要素が個別に参照されます。個々の要素を引用する拡張は、シェルが空白に値を分割しないことを保証します(そして分割された単語に対してファイル名のグロービングを実行しません)。
また、見ることができます
/bin/sh
名前付き配列を使用せずにこれを実行することもできます。代わりに、位置引数リストを使用してデータを保持し、リストの各部分を特別な単語(END
選択したランダムな文字列であるを使用)で終了します。次にリストを繰り返し、リストから要素を削除します。
#!/bin/sh
set -- 127.0.0.1 localhost alpha beta gamma theta END \
8.8.8.8 dns itsy bitsy 'spider man' END
while [ "$#" -gt 0 ]; do
if ping -c 3 "$1" >/dev/null; then
printf '%s\n' "$2"
shift 2
while [ "$1" != END ]; do
printf '\t%s\n' "$1"
shift
done
else
while [ "$1" != END ]; do shift; done
fi
shift
done
答え2
この回答はあなたの問題を直接解決するものではありませんが、問題に対する代替ソリューションを提供します。配列に依存しません。
配列を扱う代わりにファイルを使用します。私の考えでは、ファイルを使用するとプログラムからデータを分離できるという利点があります。作成とメンテナンスが簡単です。
これを行うには、「共有」をカンマ,
または別の文字で区切ります。
ファイル.txt
127.0.0.1 localhost aaa,nnn,cvcc
8.8.8.8 dns bbb,tttt,rrrr
failedip failed a,b,c
スクリプト:
#!/bin/bash
# loop over the file's lines
while IFS=' ' read -r ip domain share; do
# a blank line to separate results at each loop
echo
# perform the `ping`, redirect to `/dev/null` if you don't need to print the output
if ping -c3 "$ip" &> /dev/null;then
echo "ping to $ip successful"
echo "domain: $domain"
# change the IFS to comma ',' in a subshell to parse the 'shares'
(IFS=,; printf "share: %s\n" $share)
else
# message if `ping` failed
echo "ping to $ip failed"
fi
done < file.txt
出力:
ping to 127.0.0.1 successful
domain: localhost
share: aaa
share: nnn
share: cvcc
ping to 8.8.8.8 successful
domain: dns
share: bbb
share: tttt
share: rrrr
ping to failedip failed
答え3
for n in ${A} ${B} ; do
これはあなたが望むことをしません。インデックスなしで配列を取得することは、インデックス0の要素を取得するのと${A}
同じ${A[0]}
ですB
。ループは$n
各値を1つずつ設定するため、最初の${A[0]}
反復を実行してから${B[0]}
2回目の反復を実行します。
${n[0]}
配列ではないなどにも同様に適用されるので、${n[1]}
そこには何もなく、他のすべては設定されていないだけです。${n[2]}
$n
${n[0]}
Bashは実際に2D配列を処理しませんが、次のように構造を反転できます。
ips=(127.0.0.1 8.8.8.8)
names=(localhost dns)
for i in "${!ips[@]}"; do
if ping -c3 "${ips[i]}"; then
echo "host ${names[i]-"(unknown")} is up"
fi
done
ただし、とにかく別のファイルにデータを保存する必要があります。
Zshでは、データ構造とループに関連するすべてが異なる可能性があり、IIRC kshもBashよりも優れたデータ構造サポートを提供します。