I am trying to run a simple script in debug mode.
#!/bin/bash
trap 'read -p "run: $BASH_COMMAND"' DEBUG
command 1
command 2
**Current output:**
run: command 1 <press enter and the command executes>
run: command 2 <press enter and the command executes>
But I want to run this in a loop asking yes/no before every execution
Expected output:
run: command 1 yes/no? <input 'yes' + enter and the command executes>
run: command 2 yes/no? <input 'yes' + enter and the command executes>
I tried
trap [['read -p "run: $BASH_COMMAND" && "continue [y/n]" ' ; echo $REPLY)" == [Yy]* ]] && echo Continuing || echo Stopping DEBUG
but I am not able to figure it out.
Basically, I am trying to perform two read operation in trap/debug command and on second read i want to perform logical operation before executing.
Could anyone point me in the right direction, please? May be process substitution
Perhaps something like this
#! /bin/bash
confirm() {
read -rp "run: $BASH_COMMAND, continue [y/n]: "
if [[ "$REPLY" == [Yy]* ]]; then
echo Continuing
else
echo Stopping DEBUG
exit
fi
}
trap confirm DEBUG
command 1
command 2
Related
Write a single line ‘if-then-else’ command that prints 1 if vi is running and 0 if it does not.
I wrote:
if [ $.vi -eq 1 ]; then echo "1"; else echo "0"; fi
I don't think that is right. How would I write the command that would print 1 if vi is running?
Thats a bad way, Try like this to check if process (vi) is running
if pgrep -x "vi" > /dev/null
then
echo "1"
else
echo "0"
fi
You can also try ps -C vi and all the other if statements and redirection would be the same.
Currently trying to write bash that will do the following.
check if curl is installed
print out "which curl" before running it so that the user is able to opt in/out of running something they consider unsafe.
Use case is when you download a big script from github and you want to have more control over what it is doing. Also to be more aware of how it works.
I am not sure how to include this opt in/out code without messing up the "return" echo. Maybe the answer is to use something different that the read -n 1 -s -r -p code. I like that solution because it allows hitting any key to continue.
To be clear. If I check for YES/NO later on, it is messed up because it will contain the character used to continue by pressing any key. In my output example the space bar was hit to continue
#! /bin/bash
# Returns YES if installed otherwise return NO
check_curl_installed() {
echo >&2 "Before running, the command will be printed below."
echo >&2 "Press any key to approve running it"
read -n 1 -s -r -p "which curl"
echo ""
if which curl > /dev/null; then
echo "YES"
else
echo "NO"
fi
}
main() {
RESULT=$(check_curl_installed)
echo $RESULT
echo x${RESULT}x
}
main "$#"
exit 0
This is the output
user#computer:tmp$ ./check_curl_installed.sh
Before running, the command it will be printed below.
Press any key to approve running it
which curlYES
x YESx
Instead of using the output of the function, use its exit status.
check_curl_installed() {
echo >&2 "Before running, the command will be printed below."
echo >&2 "Press any key to approve running it"
read -n 1 -s -r -p "which curl"
echo ""
if which curl > /dev/null; then
return 0
else
return 1
fi
}
if check_curl_installed
then
# do something
else
# do something else
fi
how about this modified version to get only the Y key to answer...
#! /bin/bash
# Returns YES if installed otherwise return NO
check_curl_installed() {
echo >&2 "Before running, the command will be printed below."
echo >&2 "Press Y key to approve running it"
read -n 1 -r -s -p "Which curl?"
if [[ $REPLY =~ ^[Yy]$ ]]; then
if which curl > /dev/null ; then
printf "\nYES It is installed\n"
else
printf "\nNO It is not installed\n"
fi
else
printf "\nExiting - not checking\n"
fi
}
main() {
check_curl_installed
}
main "$#"
exit 0
Your echo result is, i think just pulling the first line of the check_curl_installed function...
Maybe if result was set to an array?
my testing around has shown that it's forgetting variables in the function at the higher main function. I even tried exporting to get the main function to work, but to no avail. I'm not super strong in bash, so i apologize on that.
Also might work better to put the echos inside each function, instead of shoving them into a variable...
Most, if not all, languages, only return one value from a function. Maybe this is why your output don't do as you want? a quick search brought this up https://unix.stackexchange.com/questions/408543/how-can-a-bash-function-return-multiple-values
I read a lot about passing piping stdin to bash read function, but nothing seems to work for my bash version!!
GNU bash, version 3.2.51(1)-release (x86_64-suse-linux-gnu)
I have a bash script that in some point asks the user "yes/no" with variable CONTINUEQUESTION:
echo "Do you want to continue? (yes/no):"
read CONTINUEQUESTION
tmp=$(tr '[:upper:]' '[:lower:]' <<<$CONTINUEQUESTION)
if [[ "$tmp" != 'y' && "$tmp" != 'yes' ]]; then
echo "Aborting because of input '$CONTINUEQUESTION'"
exit
fi
I would like to pipe a "yes or no" to this question without user input!
Yes i know i could use expect, but i don't prefer it in this case.
So i tried several things:
CONTINUEQUESTION='yes'
echo $CONTINUEQUESTION | ./myscript.sh
Aborting because of input ''
./myscript.sh <<< "$CONTINUEQUESTION"
Aborting because of input ''
...and many other, nothing worked!?
O.k. now I did a bit revers thinking and find out that the below line causes the problem with the pipe...because when i remarked it out all the below answers are working just fine, but not when this line is executed:
running=`ssh root#${HOSTNAME} 'su - root -c "/bin/tools list | grep \"system running\"" 2>&1'`
But, i need this line before the read! What do i need to reverse the 2>&1????
My script look like this and is working without this try to over come the user intervantion:
LIST_FILE_NAME=$1
STILL_RUNNING=0
running=`ssh root#${HOSTNAME} 'su - root -c "cat '$LIST_FILE_NAME' | grep \"system running\"" 2>&1'`
if [[ $running =~ .*running.* ]]; then
STILL_RUNNING=1
echo "NODE $NODE running stop before continuing."
fi
if [ $STILL_RUNNING -eq 1 ]; then
echo "Aborting system was still running!"
exit 1
fi
echo "Do you want to continue? (yes/no):"
read CONTINUEQUESTION
tmp=$(tr '[:upper:]' '[:lower:]' <<<$CONTINUEQUESTION)
if [[ "$tmp" != 'y' && "$tmp" != 'yes' ]]; then
echo "Aborting because of input '$CONTINUEQUESTION'"
exit
fi
echo "o.k."
4 points:
list.log can have a line with "system running" or "system notrunning"
if list.log has a line with "system notrunning" than the bash script continue towards the question
at the question i never got it right to inject the 'y' or 'yes' so the bash aborts because of input ''
i execute this like: ./myscript.sh list list.log (normal way)
This bash runs well if the user interacts at the question!
Thanks for you time!!!
Consider this variation as well:
#!/bin/bash
read -p "Do you want to continue? (yes/no): " CONTINUEQUESTION
if [[ $CONTINUEQUESTION != [Yy] && $CONTINUEQUESTION != [Yy][Ee][Ss] ]]; then
echo "Aborting because of input '$CONTINUEQUESTION'."
exit
fi
Tested with:
bash script.sh <<< yes
If it doesn't work, show the output of:
bash -x script.sh <<< yes
Your line
$CONTINUEQUESTION='yes'
shoul really be
CONTINUEQUESTION='yes'
I am not sure then that your are feeding stdin with the word 'yes'. You could add an echo after the read to be sure.
You can use heredoc:
bash -ex ./myscript.sh << 'EOF'
yes
EOF
Search for Here Documents in man bash.
EDIT: Based on comments you can use this ssh command:
running=$(ssh -t -t root#${HOSTNAME} "grep 'system running' \"$LIST_FILE_NAME\"")
when I use read statement in shell
read -n 1 -s -t 5 -p "Starting the script in 5 seconds. Press any key to stop!" yn
How to check if any key is pressed or not , if a key is pressed then the script must exit otherwise , the script must continue ?
You can use loop and limit read's time by one second:
#!/bin/bash
shouldStop=0
for (( i=5; i>0; i--)); do
printf "\rStarting script in $i seconds. Press any key to stop!"
read -s -n 1 -t 1 key
if [ $? -eq 0 ]
then
shouldStop=1
fi
done
if [ $shouldStop==1 ]
then
printf "do not run script"
else
printf "run script"
fi
Simply:
read -n 1 -s -t 5 -p "Starting the script in 5 seconds. Press any key to stop!" && \
exit 1
When a key is read, read returns 0 which would allow && to process the next statement exit 1. This would end your script.
You don't have to specify a variable as well so you wouldn't need it. read uses default variable $REPLY.
I'm currently writing a bash script to do tasks automatically. In my script I want it to display progress message when it is doing a task.
For example:
user#ubuntu:~$ Configure something
->
Configure something .
->
Configure something ..
->
Configure something ...
->
Configure something ... done
All the progress message should appear in the same line.
Below is my workaround so far:
echo -n "Configure something "
exec "configure something 2>&1 /dev/null"
//pseudo code for progress message
echo -n "." and sleep 1 if the previous exec of configure something not done
echo " done" if exec of the command finished successfully
echo " failed" otherwise
Will exec wait for the command to finish and then continue with the script lines later?
If so, then how can I echo message at the same time the exec of configure something is taking place?
How do I know when exec finishes the previous command and return true? use $? ?
Just to put the editorial hat on, what if something goes wrong? How are you, or a user of your script going to know what went wrong? This is probably not the answer you're looking for but having your script just execute each build step individually may turn out to be better overall, especially for troubleshooting. Why not define a function to validate your build steps:
function validateCmd()
{
CODE=$1
COMMAND=$2
MODULE=$3
if [ ${CODE} -ne 0 ]; then
echo "ERROR Executing Command: \"${COMMAND}\" in Module: ${MODULE}"
echo "Exiting."
exit 1;
fi
}
./configure
validateCmd $? "./configure" "Configuration of something"
Anyways, yes as you probably noticed above, use $? to determine what the result of the last command was. For example:
rm -rf ${TMP_DIR}
if [ $? -ne 0 ]; then
echo "ERROR Removing directory: ${TMP_DIR}"
exit 1;
fi
To answer your first question, you can use:
echo -ne "\b"
To delete a character on the same line. So to count to ten on one line, you can do something like:
for i in $(seq -w 1 10); do
echo -en "\b\b${i}"
sleep .25
done
echo
The trick with that is you'll have to know how much to delete, but I'm sure you can figure that out.
You cannot call exec like that; exec never returns, and the lines after an exec will not execute. The standard way to print progress updates on a single line is to simply use \r instead of \n at the end of each line. For example:
#!/bin/bash
i=0
sleep 5 & # Start some command
pid=$! # Save the pid of the command
while sleep 1; do # Produce progress reports
printf '\rcontinuing in %d seconds...' $(( 5 - ++i ))
test $i -eq 5 && break
done
if wait $pid; then echo done; else echo failed; fi
Here's another example:
#!/bin/bash
execute() {
eval "$#" & # Execute the command
pid=$!
# Invoke a shell to print status. If you just invoke
# the while loop directly, killing it will generate a
# notification. By trapping SIGTERM, we suppress the notice.
sh -c 'trap exit SIGTERM
while printf "\r%3d:%s..." $((++i)) "$*"; do sleep 1
done' 0 "$#" &
last_report=$!
if wait $pid; then echo done; else echo failed; fi
kill $last_report
}
execute sleep 3
execute sleep 2 \| false # Execute a command that will fail
execute sleep 1