@@ -38,7 +38,7 @@ ssh_opts="-oBatchMode=yes \
38
38
-oForwardX11=no \
39
39
-oStrictHostkeyChecking=no"
40
40
41
- unset color flock footer lockfile header host_list
41
+ unset cleanup_files color exitfile flock footer lockfile header host_list
42
42
abbrev=false
43
43
active_threads=0
44
44
delay=0
@@ -88,6 +88,7 @@ Additional options:
88
88
* -u username execute commands as 'username'
89
89
* -s timeout set how long to wait before timing out (in seconds)
90
90
* -t num_threads limit the number of parallel threads (implies -p)
91
+ * -x exit_file write the exit status for each host to exit_file
91
92
* -y allocate PTY (enables screen-based apps and job control)
92
93
93
94
EOM
@@ -156,12 +157,13 @@ ssh_host() {
156
157
[[ ${exit_code} -eq 255 ]] && error=true
157
158
158
159
if [[ ${error} == true || ${quiet} == false ]]; then
160
+ host_display=" ${host} "
159
161
if [[ ${color} == true ]]; then
160
162
c=${def_color} ; [[ ${error} == true ]] && c=${err_color}
161
- host =$' \e [0;' ${c} ' m' " ${host} " $' \e [0m'
163
+ host_display =$' \e [0;' ${c} ' m' " ${host} " $' \e [0m'
162
164
fi
163
165
164
- header=" -- ${host } --" $' \n '
166
+ header=" -- ${host_display } --" $' \n '
165
167
footer=$' \n '
166
168
output=" ${header}${output}${footer} "
167
169
fi
@@ -175,7 +177,12 @@ ssh_host() {
175
177
fi
176
178
177
179
# acquire lock and print output
178
- ( lock; kill -s SIGUSR1 $$ ; echo -n " ${output} " ) 40> " ${lockfile} "
180
+ (
181
+ lock
182
+ kill -s SIGUSR1 $$
183
+ echo -n " ${output} "
184
+ echo -e " ${exit_code} \t${host} " >> " ${exitfile} "
185
+ ) 40> " ${lockfile} "
179
186
}
180
187
181
188
ssh_live () {
@@ -202,16 +209,21 @@ ssh_live() {
202
209
ssh ${ssh_opts} ${host} ${@ } 2>&1 | while read line; do
203
210
echo " ${hname}${line} "
204
211
done
212
+ exit_code=${PIPESTATUS[0]}
205
213
206
214
if [[ " ${delay} " -gt 0 ]]; then
207
215
sleep " ${delay} "
208
216
fi
209
217
210
218
# notify our 'thread pool' that the next task can run
211
- ( lock; kill -s SIGUSR1 $$ ) 40> " ${lockfile} "
219
+ (
220
+ lock
221
+ kill -s SIGUSR1 $$
222
+ echo -e " ${exit_code} \t${host} " >> " ${exitfile} "
223
+ ) 40> " ${lockfile} "
212
224
}
213
225
214
- while getopts " aAcd:ef:i:jl:o:pqu:s:t:y" flag; do
226
+ while getopts " aAcd:ef:i:jl:o:pqu:s:t:x: y" flag; do
215
227
case ${flag} in
216
228
a) cmd=" ${cmd_live} " ; abbrev=false ;;
217
229
A) cmd=" ${cmd_live} " ; abbrev=true ;;
@@ -230,6 +242,7 @@ while getopts "aAcd:ef:i:jl:o:pqu:s:t:y" flag; do
230
242
u) ssh_opts=" ${ssh_opts} -l${OPTARG} " ;;
231
243
s) ssh_opts=" ${ssh_opts} -oConnectTimeout=${OPTARG} " ;;
232
244
t) parallel=true; max_threads=${OPTARG} ;;
245
+ x) exitfile=" ${OPTARG} " ;;
233
246
y) ssh_opts=" ${ssh_opts} -t -t" ;;
234
247
? ) error_die ;;
235
248
esac
@@ -271,9 +284,17 @@ if [[ ${parallel} == false ]] ; then
271
284
max_threads=1
272
285
fi
273
286
274
- lockfile=" ${TMPDIR:-/ tmp} /dssh.$$ .$RANDOM .lock"
287
+ lock_base=" ${TMPDIR:-/ tmp} /dssh.$$ .$RANDOM "
288
+ lockfile=" ${lock_base} .lock"
289
+ cleanup_files=" ${lockfile} "
275
290
touch " ${lockfile} "
276
- trap ' rm -f ${lockfile}' EXIT
291
+
292
+ if [[ -z " ${exitfile} " ]]; then
293
+ exitfile=" ${lock_base} .exit"
294
+ cleanup_files=" ${cleanup_files} ${exitfile} "
295
+ fi
296
+
297
+ trap ' rm -f ${cleanup_files}' EXIT
277
298
278
299
set -f # Temporarily disable pathname expansion
279
300
for host in ${hosts} ; do
299
320
set +f
300
321
301
322
until wait ; do : ; done
323
+
324
+ status=" $( sort -n " ${exitfile} " 2> /dev/null | tail -n 1 | cut -f1) " 2> /dev/null
325
+ if [[ -n " ${status} " ]]; then
326
+ exit " ${status} "
327
+ fi
0 commit comments