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 | #!/bin/bash
# qtail.sh - run just like qsub, but:
# (1) It also runs tail on the output and error files, so it "feels" like an
# interactive session
# (2) If you kill the tail function, it kills the qsub job. This is useful
# for debugging. If it is not desired, either delete the last while
# loop, or add an option to not perform that loop
# Author: Andrew M. Chap
# Last edited August 2018
# Trap function so we kill the qsub job when we kill our qtail function
function finish {
echo deleting jobID $jobID
qdel $jobID
}
# start main function
function qtail {
# First argument must be the qsub file
qsubFile=$1
# Store the rest of the arguments (including options)
otherArgs="${@:2}"
# Get the name of the file before the extension via parameter expansion
qsubName=${qsubFile%%.*}
echo qsubName is $qsubName
# Get the name of the error and output files
for errout in err out
do
flag="-${errout:0:1}" # flag for err is "-e" and out is "-o"
# First, look in the passed arguments for -e or -o options
file=$(echo $otherArgs | sed -n -e "s|^.*$flag ||p") # get everything after flag
file=${file/%\ */} # keep first word only
# If we didn't find any -e or -o options in arguments, search the qsub file
# for these arguments
if [ -z "$file" ]
then
file=$(sed -n -e "s|^.*$flag ||p" $qsubFile)
fi
# If we still didn't find them, then they were unspecified, so we will name
# them with the same name as the job name
if [ -z "$file" ]
then
file=$qsubName.$errout
fi
# Assign to error file or output file
if [ $errout == err ]
then
errFile=$file
elif [ $errout == out ]
then
outFile=$file
fi
done
# if error or output files exist, remove them
rm $outFile $errFile 2> /dev/null
# create error and output files
touch $outFile $errFile
jobOutput=$(qsub $qsubFile $otherArgs)
# ID number of the job is the first number output by the qsub command
jobID=$(echo $jobOutput | sed -e "s|\([0-9]\+\).*|\1|")
echo jobID is $jobID
# setup exit trap, so that if we kill this function it kills the qsub job too
trap finish SIGINT EXIT SIGTERM INT
# Launch tail function as a subshell but redirect output back to stdout
exec 3>&1 # creates 3 as alias for 1
$(tail -f $outFile -f $errFile >&3) & #>&3 & # tail both the out and error files
# get PID of tail so we can terminate it when qsub job is complete
TAIL_PID=$!
# check every second the status of the job and kill TAIL_PID if the job is complete
stillRunning=True
while [[ "$stillRunning" == 'True' ]]
do
if qstat $jobID | grep ' C '
then
echo job is complete
kill -9 $TAIL_PID
stillRunning=False
echo qsub complete
fi
sleep 1
done
}
|