Estou trabalhando em um script de shell um pouco complicado pela primeira vez e abaixo está o que ele deve fazer:
- Durante a inicialização, descobre qual é minha
clientid
, observando o arquivo host-mapping.txt
. Se não conseguir encontrar clientid
para o meu nome de host, preciso sair do script de shell com código de status diferente de zero e registrar a mensagem de erro.
- Agora, depois que eu tiver o
clientid
válido, extrairei primary files
do arquivo primary-mappings.txt
e secondary files
do arquivo secondary-mappings.txt
para esse clientid
válido. Se, por qualquer motivo, não conseguir encontrar arquivos primários ou secundários para esse clientid
desse arquivo, então sairei do shell script e registrarei uma mensagem de erro.
- Agora, quando eu tiver arquivos primários e secundários válidos para esse
clientid
, então, vou começar a copiar esses arquivos em paralelo usando gnu-parallel
de local_server
. Todos os arquivos primários irão para a pasta primary
e todos os arquivos secundários irão para a pasta secondary
. Se os arquivos não estiverem na pasta hold1
nos servidores remotos, eles deverão estar lá na pasta hold2
.
- Agora, assim que todos os arquivos forem copiados, verificarei no final se todos os arquivos primários e secundários estão presentes para o
clientid
nessas duas pastas, mas se por algum motivo eu não encontrar esses arquivos, então eu deseja sair do shell script com uma mensagem que informa quais arquivos estão faltando.
Abaixo está meu script e ele faz o trabalho, mas eu gostaria de ver se há alguma maneira melhor ou mais eficiente de fazer as coisas acima, já que esta é a primeira vez que escrevo um script pouco complicado, então queria verificar isso. A partir de agora, não tenho mecanismo para sair do shell script, se não conseguir encontrar primary
ou secondary
arquivos para esse clientid
e também não tenho mecanismo para sair do shell script se durante o fase de verificação, alguns arquivos estão faltando.
#!/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}=\[([^]\]+).*//; 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."
Abaixo está o meu arquivo host-mapping.txt
e ele terá muito mais entradas. Aqui valor é um nome de host válido e a chave será string "k" seguida por algum número e esse número deve estar lá nos arquivos de mapeamento.
k1=machineA.abc.com
k2=machineB.abc.com
k3=machineC.def.com
k4=machineD.pqr.com
k5=machineO.abc.com
E abaixo estão meus arquivos de mapeamento de amostra:
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]}
Por exemplo: clientid
1 tem 343, 0, 686, 1372, 882, 196
arquivos primários e 1152, 816, 1488, 336, 1008
arquivos secundários. Similarmente para outros clientids
também.