-
Notifications
You must be signed in to change notification settings - Fork 12
/
threads.sh
234 lines (192 loc) · 5.33 KB
/
threads.sh
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/usr/bin/env bash
#set -x
export PS4='+ [`basename ${BASH_SOURCE[0]}`:$LINENO ${FUNCNAME[0]} \D{%F %T} $$ ] '
PATH="$PATH:/usr/bin:/bin:/sbin:/usr/sbin"
export PATH
SSH="ssh -n -o PasswordAuthentication=no -o StrictHostKeyChecking=no -o ConnectTimeout=5 "
SCP='scp -q -r -o PasswordAuthentication=no -o StrictHostKeyChecking=no -o ConnectTimeout=5 '
TMPFILE="pipe.$$"
CURDIR=$(cd "$(dirname "$0")"; pwd);
MYNAME="${0##*/}"
g_HOST_LIST=""
g_THREAD_NUM=30
g_PORT=22
g_LIMIT=0
RET_OK=0
RET_FAIL=1
##################### function #########################
_report_err() { echo "${MYNAME}: Error: $*" >&2 ; }
if [ -t 1 ]
then
RED="$( echo -e "\e[31m" )"
HL_RED="$( echo -e "\e[31;1m" )"
HL_BLUE="$( echo -e "\e[34;1m" )"
NORMAL="$( echo -e "\e[0m" )"
fi
_hl_red() { echo "$HL_RED""$@""$NORMAL";}
_hl_blue() { echo "$HL_BLUE""$@""$NORMAL";}
_trace() {
echo $(_hl_blue ' ->') "$@" >&2
}
_print_fatal() {
echo $(_hl_red '==>') "$@" >&2
}
_is_number() {
local re='^[0-9]+$'
local number="$1"
if [ "x$number" == "x" ]; then
_print_fatal "error: _is_number need one parameter"
exit 1
else
number=${number//[[:space:]]/}
fi
if [[ $number =~ $re ]] ; then
return 0
else
_print_fatal "error: ${number} not a number" >&2
exit 1
fi
}
readlinkf() { perl -MCwd -e 'print Cwd::abs_path shift' $1;}
# ABSPATH="$(readlinkf ./non-absolute/file)"
_usage() {
cat << USAGE
Usage: bash ${MYNAME} [options] hostlist command.
Options:
-c, --concurrent num Thread Nummber for run the command at same time, default: 1.
-s, --ssh Use ssh authorized_keys to login without password query from DB.
-p, --port port Use port instead of defult port:22.
-l, --limit num Limit num for host to run when limit less then all host num.
-h, --help Print this help infomation.
Require:
hostlist Machine list filename for operation.
command Command string for run in every machine.
Notice:
please check the result output under log/hostname.
USAGE
exit $RET_OK
}
#
# Parses command-line options.
# usage: _parse_options "$@" || exit $?
#
_parse_options()
{
declare -a argv
while [[ $# -gt 0 ]]; do
case $1 in
-c|--concurrent)
g_THREAD_NUM="${2}"
_is_number "${g_THREAD_NUM}"
shift 2
;;
-s|--ssh)
g_NOPASSWD=1
shift
;;
-p|--port)
g_PORT=${2}
_is_number "${g_PORT}"
shift 2
;;
-l|--limit)
g_LIMIT=${2}
_is_number "${g_LIMIT}"
shift 2
;;
-h|--help)
_usage
exit
;;
--)
shift
argv=("${argv[@]}" "${@}")
break
;;
-*)
_print_fatal "command line: unrecognized option $1" >&2
return 1
;;
*)
argv=("${argv[@]}" "${1}")
shift
;;
esac
done
case ${#argv[@]} in
2)
command -v greadlink >/dev/null 2>&1 && g_HOST_LIST=$(greadlink -f "${argv[0]}") || g_HOST_LIST=$(readlink -f "${argv[0]}")
g_CMD="${argv[1]}"
;;
0|*)
_usage 1>&2
return 1
;;
esac
}
################################## main route #################################
_parse_options "${@}" || _usage
if [ ! -e $g_HOST_LIST ]; then
_print_fatal "machine list file $g_HOST_LIST is not exist."
_usage
fi
g_CMD=${g_CMD//[[:space:]]/}
if [ x"$g_CMD" == "x" ]; then
_print_fatal "command string is null."
_usage
fi
if [ -d log ]; then
rm -rf log
fi
mkdir -p log
mkfifo ${TMPFILE}
exec 9<>${TMPFILE}
#trap "rm -f ${TMPFILE}; exit" INT TERM EXIT
cleanup() { if [ -e ${TMPFILE} ]; then rm -f "${TMPFILE}" ; fi }
trap cleanup EXIT TERM EXIT;
#trap 'rm -f "${TMPFILE}"; exit $?' INT TERM EXIT
_trace "You run command: $HL_BLUE $g_CMD $NORMAL"
_trace "Notice:(${HL_RED}Ctrl+C for cancel,${NORMAL} ENTER for continue, wait for 30s continue auto.)"
read -t 30 word # wait for 30 sec for waiting input.
for ((i=0;i<${g_THREAD_NUM};i++))
do
echo >&9
done
unset HOST
INDEX=0
while read -r HOST
do
HOST=${HOST#*(:space:)}
(( INDEX++ ))
fchar=`echo ${HOST} | cut -c -1`
if [ "x${HOST}" == "x" ]; then
_print_fatal "Notice: null string for hostname."
continue
elif [ "x$fchar" = "x#" ]; then
host=`echo $HOST | cut -c 2-`
_print_fatal "[$INDEX] Warn: skip ${host}"
unset host
continue
fi
unset fchar
if [ "x$g_LIMIT" != "x0" ]; then
if [ "$g_LIMIT" -lt "$INDEX" ]; then
_trace "Reach limit num of $g_LIMIT"
break
fi
fi
_trace "[$INDEX] start ${HOST} ......"
read <&9
ping -c 1 -W 3 ${HOST} &>/dev/null
if [ $? -ne 0 ]; then
_print_fatal "[$INDEX] Error: ${HOST} is unreachable."
echo >&9
continue
fi
(${SSH} "${HOST}" "-p ${g_PORT}" "${g_CMD}" &>${CURDIR}/log/${HOST}; echo >&9) &
#(${SSH} ${HOST} "ls " &> log/${HOST}; echo >&9) &
done < ${g_HOST_LIST}
wait
rm -f ${TMPFILE}
#trap - INT TERM EXIT
exec 9<&-