私は少し複雑なシェルスクリプトに初めて取り組んでおり、以下はそれが何をすべきかです:
Host-mapping.txt
ファイルを調べて、私のclientid
が何であるかを判断します。ホスト名のclientid
が見つからない場合は、ゼロ以外のステータスコードとログエラーメッセージを使用してシェルスクリプトを終了する必要があります。clientid
を取得したら、その有効なclientid
に対してprimary files
ファイルからprimary-mappings.txt
を抽出し、secondary files
ファイルからsecondary-mappings.txt
を抽出します。何らかの理由で、そのファイルからそのclientid
のプライマリファイルまたはセカンダリファイルが見つからない場合は、シェルスクリプトを終了し、エラーメッセージをログに記録します。clientid
の有効なプライマリファイルとセカンダリファイルを取得したら、gnu-parallel
からlocal_server
を使用してこれらのファイルの並列コピーを開始します。すべてのプライマリファイルはprimary
フォルダーに移動し、すべてのセカンダリファイルはsecondary
フォルダーに移動します。リモートサーバーのhold1
フォルダーにファイルがない場合は、hold2
フォルダーにあるはずです。clientid
のすべてのプライマリファイルとセカンダリファイルが存在することを確認しますが、何らかの理由でそれらのファイルが見つからない場合は、不足しているファイルを通知するメッセージを表示してシェルスクリプトを終了したい。以下は私のスクリプトであり、それは仕事をしますが、これは少し複雑なスクリプトを書くのは初めてなので、これをチェックしたかったので、上記のことを行うためのより良いまたは効率的な方法があるかどうかを確認したいと思います。現在のところ、そのprimary
のsecondary
またはclientid
ファイルが見つからない場合、シェルスクリプトを終了するメカニズムがありません。また、メカニズムもありません。検証フェーズ中に一部のファイルが欠落している場合にシェルスクリプトを終了します。
#!/bin/bash
path=/home/goldy/scripts
mapfiles=(primary-mappings.txt secondary-mappings.txt)
hostfile=Host-mapping.txt
machines=(machine1769.abc.Host.com proctek5461.def.Host.com letyrs87541.pqr.Host.com)
# folders on local box where to copy files
primary=/data01/primary
secondary=/data02/secondary
# folders on remote servers from where to copy files
export hold1=/data/snapshot/$1
export hold2=/data/snapshot/$2
date1=$(date +"%s")
# this will tell me what's my clientid given my current hostname
getProperty () {
prop_value=$(hostname -f)
prop_key=`cat $path/$hostfile | grep "$prop_value" | cut -d'=' -f1`
echo $(echo $prop_key | tr -dc '0-9')
}
# if I can't find clientid for my hostname, then I will log a message
# and exit out of Shell script with non zero status code
clientid=$(getProperty)
[ -z "$clientid" ] && { echo "cannot find clientid for $(hostname -f)"; exit 1; }
# now once I have valid clientid, then I will get primary and secondary mapping
# from the "Host-mapping.txt" file
declare -a arr
mappingsByClientID () {
id=$1 # 1 to 5
file=$path/${mapfiles[$2]} # 0 to 1
arr=($(sed -r "s/.*\b${id}=\[([^]\]+).*/\1/; s/,/ /g" $file))
echo "${arr[@]}"
}
# assign output of function to an array
pri=($(mappingsByClientID $clientid 0))
snd=($(mappingsByClientID $clientid 1))
echo "primary files: ${pri[@]}"
echo "secondary files: ${snd[@]}"
# figure out which machine you want to use to start copying files from
case $(hostname -f) in
*abc.Host.com)
local_server=("${machines[0]}")
;;
*def.Host.com)
local_server=("${machines[1]}")
;;
*pqr.Host.com)
local_server=("${machines[2]}")
;;
*) echo "unknown Host: $(hostname -f), exiting." && exit 1 ;;
# ?
esac
export local="$local_server"
# deleting files before we start copying
find "$primary" -maxdepth 1 -type f -exec rm -fv {} \;
find "$secondary" -maxdepth 1 -type f -exec rm -fv {} \;
do_copy() {
el=$1
primsec=$2
(scp -C -o StrictHostKeyChecking=no goldy@"$local":"$hold1"/hello_monthly_"$el"_999_1.data "$primsec"/. > /dev/null 2>&1) || (scp -C -o StrictHostKeyChecking=no goldy@"$local":"$hold2"/hello_monthly_"$el"_999_1.data "$primsec"/. > /dev/null 2>&1)
}
export -f do_copy
# copy files in parallel
parallel -j "$3" do_copy {} $primary ::: ${pri[@]} &
parallel -j "$3" do_copy {} $secondary ::: ${snd[@]} &
wait
echo "all files copied"
# this is for verification to see all files got copied or not
# in primary and secondary folder
set -- "$primary" "$secondary"
typeset -n array
for array in pri snd; do
for num in "${array[@]}"; do
name="hello_monthly_${num}_999_1.data"
if [ ! -f "$1/$name" ]; then
{ echo "$name" not found in "$1" >&2 && exit 1; }
fi
done
shift
done
date2=$(date +"%s")
diff=$(($date2-$date1))
echo "Total Time Taken - $(($diff / 3600)) hours and $(((diff/60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
以下は私のHost-mapping.txt
ファイルで、さらに多くのエントリがあります。ここで、値は有効なホスト名であり、キーは文字列「k」の後にいくつかの番号が続き、その番号はマッピングファイルに存在する必要があります。
k1=machineA.abc.com
k2=machineB.abc.com
k3=machineC.def.com
k4=machineD.pqr.com
k5=machineO.abc.com
以下は私のサンプルマッピングファイルです:
primary_mappings.txt
{1=[343, 0, 686, 1372, 882, 196], 2=[687, 1, 1373, 883, 197, 736, 1030, 1569], 3=[1374, 2, 884, 737, 198, 1570], 4=[1375, 1032, 1424, 3, 885, 1228], 5=[1033, 1425, 4, 200, 886]}
secondary_mappings.txt
{1=[1152, 816, 1488, 336, 1008], 2=[1153, 0, 817, 337, 1489, 1009, 1297], 3=[1, 1154, 1490, 338], 4=[1155, 2, 339, 1491, 819, 1299, 1635], 5=[820, 1492, 340, 3, 1156]}
例:clientid
1には343, 0, 686, 1372, 882, 196
プライマリファイルと1152, 816, 1488, 336, 1008
セカンダリファイルがあります。他のclientids
についても同様です。
いくつか提案があるので、答えを書こうと思いました。
スクリプトではprimary_mappings.txt
およびsecondary_mappings.txt
と呼ばれるprimary-mappings.txt
およびsecondary-mappings.txt
に関して不整合があります。もちろん、ファイルの名前を変更する(またはスクリプトの名前を変更する)必要があります。
STDERRへのロギングとプログラムの終了を処理する2つの関数を作成します。これには、読みやすさが向上し、エラーが発生しにくく、関数呼び出し内から終了できるという利点があります(応答シェルスクリプトを終了するメカニズムがありません):
trap "exit 1" TERM
export TOP_PID=$$
log_error () {
echo "$1">&2;
}
log_error_and_exit () {
echo "$1">&2;
kill -s TERM $TOP_PID
}
エラーをSTDERRに記録したいようですが、STDOUTに書き込む場合があります。 >&2
をいくつか忘れただけだとすると、新しく作成した関数を使用して、それを標準化するのは簡単です。
a。
[ -z "$clientid" ] && { echo "cannot find clientid for $(hostname -f)"; exit 1; }
になります:
[ -z "$clientid" ] && { log_error_and_exit "Cannot find ClientID for $(hostname -f)"; }
b。
*) echo "unknown Host: $(hostname -f), exiting." && exit 1 ;;
になります:
*) log_error_and_exit "Unknown Host: $(hostname -f), exiting." ;;
あなたはこれをするのを忘れたようです:
何らかの理由で、そのファイルからそのクライアントIDのプライマリファイルまたはセカンダリファイルが見つからない場合は、シェルスクリプトを終了し、エラーメッセージをログに記録します。
mappingsByClientID () {
id=$1 # 1 to 5
file=$path/${mapfiles[$2]} # 0 to 1
if [[ $(< $file) != *" $1="* ]]; then
log_error_and_exit "ClientID $1 out of range for $file";
fi
arr=($(sed -r "s/.*\b${id}=\[([^]\]+).*/\1/; s/,/ /g" $file))
echo "${arr[@]}"
}
あなたは現在これをしていません:
何らかの理由でそれらのファイルが見つからない場合は、不足しているファイルを通知するメッセージを表示してシェルスクリプトを終了します。
ファイルが見つからないことが判明するとすぐにexit
するので、複数のファイルが報告されることはありません。解決策は、エラーステータスを追跡する変数を作成し、検証の最後にそれをチェックすることです。
# this is for verification to see all files got copied or not
# in primary and secondary folder
set -- "$primary" "$secondary"
typeset -n array
errors=false
for array in pri snd; do
for num in "${array[@]}"; do
name="hello_monthly_${num}_999_1.data"
if [ ! -f "$1/$name" ]; then
{ log_error "$name not found in $1" && errors=true; }
fi
done
shift
done
if [ "$errors" = true ]; then
exit 1
fi