I have searched this site and google on how to timeout a bash command if it takes to long to run and have tried multiple different approaches and cant seem to get any to work.
Specifically, I need to time out 'ls | wc -l' if it takes longer than 10 seconds to run; however, I will be running the 'ls | wc -l' on multiple directories and don't want to wait 10 seconds for each one if it only takes a second to finish.
I have tried to following which only seems to kind of work, but I still have to wait to full 10 seconds when 'ls | wc -l' finishes before the 10-second sleep.
ls /file/path/to/count/ | wc -l &
pidsave=$!
sleep 1
if [ -e /proc/$pidsave ]; then
kill $pidsave; echo $?
echo 'ls command was timed out'
else
echo 'ls command completed'
fi
You can use the timeout
command:
if timeout 10 ls /file/path/to/count/ | wc -l; then
echo "Successful!!"
else
echo "Timed Out!!"
fi
Check man timeout
.
The previously posted answer also did not work for me. The problem there is that if
tests the result of wc -l
, not the actual timeout
.
To avoid this, you can either wrap the commands in a function, put the commands into an excutable file, or un-chain the commands and execute them separately, depending on what do you actually need to do with the output in your context.
The function has to be exported to subshells and then executed under a subshell.
#!/bin/bash
function my_ls {
ls | wc -l
}
export -f my_ls
timeout 10 bash -c my_ls
if [ $? -eq 0 ]; then
echo "cmd finished in time"
else
echo "cmd did NOT finish in time"
fi
Put ls | wc -l
ls | wc -l
into some file (eg /tmp/ls.sh) and make it executable ( chmod +x /tmp/ls.sh
). Use that file as the parameter for timeout
command:
#!/bin/bash
MY_FILE="/tmp/ls.sh"
echo "ls | wc -l" > $MY_FILE
chmod +x $MY_FILE
timeout 10 $MY_FILE
if [ $? -eq 0 ]; then
echo "cmd finished in time"
else
echo "cmd did NOT finish in time"
fi
Assuming the ls
is the command that is prone to taking a long time to finish in this example, run just that first. Possible output is stored in a variable (assuming the command does not time out) that you can use however you want later on:
#!/bin/bash
LIST="$(timeout 10 ls)"
if [ $? -eq 0 ]; then
echo "cmd finished in time"
echo $(wc -l <<< $LIST)
else
echo "cmd did NOT finish in time"
fi
With the help of Jiri, Option 3 did the trick. Here is the exact code I am using in case anyone is interested. I wrap this in a for statement and provided a header of Count in a light blue, TIMED OUT!!! in Red, and the actual count in Green.
echo -e "\e[1;4;36mCount\e[0m" >> $LOGPATH
for c in $DIR1 $DIR2 $DIR3 $DIR4; do
LIST=$(timeout 2 ls $c &>/dev/null; echo $?)
if [ $LIST != 0 ]; then
echo -e $c "\e[1;31mTIMED OUT!!! \e[0m" >> $LOGPATH
else
echo -e $c "\e[1;32m$(ls $c |wc -l) \e[0m" >> $LOGPATH
fi
done
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.