How to set a default value in an IF snippet? - bash

I have the following snippet in a bash script written in Solaris 10:
printf "port(389)="
read PORT
if [[ $PORT == "" ]]; then
PORT=389
fi
What I am trying to get that if the user hits the enter key, the Port should be set to 389.
The snippet above does not seem to be working.
Any suggestions?

This prompts the user for input and if enter is pressed by itself, sets the value of port to a default of "389":
read -rp "port(389)=" port
port="${port:-389}"

It's not exactly what you asked, but Solaris has a set of utilities for this sort of thing.
PORT=`/usr/bin/ckint -d 389 -p 'port(389)=' -h 'Enter a port number'`
Check out the other /usr/bin/ck* utilities to prompt the user for other types of data, including things like files or user names.

If you pass -e to read then you can use -i to specify an initial value for the prompt.

If the user enters nothing then $PORT is replaced with nothing - the ancient convention for making this work with the original Bourne shell is:
if [ "x$PORT" == "x" ]; then
Though more modern shells (i.e. actual bash, but not Solaris 10 /bin/sh which is
an ancient Bourne shell) should be able to deal with:
if [[ "$PORT" == "" ]]; then
or even
if [[ -z "$PORT" ]]; then

Another way with just the shell
-- try parameter substitution:
read port
port=${port:-389}

Related

read input from stdin but not have it echo [duplicate]

I'm trying to interpret this block of code. Searched google to see what these commands mean and no luck. I put my interpretation of what each line/block means to me. If I am wrong, please correct me. I am new to unix commands. Code:
#!/bin/bash
# input 1st command line argument for the version.
export VERSION=$1
# if user didn't input a version, print the echo message and exit (not sure what -n means but I am assuming)
if [[ ! -n "$VERSION" ]]; then
echo "Missing Version"
exit 1
fi
# creating variable UNAME that tells who the person is (their name)
export UNAME='whoami'
# no idea what -s and -p mean but i think this prints the message "enter password for $UNAME" and stores it in a new variable named PASSWORD. the $UNAME will print whatever whoami said.
read -s -p "Enter password for $UNAME: " PASSWORD
echo ""
The -p flag issues a prompt before reading input into a variable
The -s flag stop the typed response from being shown (i.e. for a sensitive password)
More information is available here:
https://linuxhint.com/bash_read_command/
-p
prompt output the string PROMPT without a trailing newline before
attempting to read.
-s
do not echo input coming from a terminal.

Why read -p won't work when use curl to get bash script? [duplicate]

I apologize in advance - I don't fully understand the ideas behind what I'm asking well enough to understand why it's not working (I don't know what I need to learn). I searched stack exchange for answers first - I found some information that seemed possibly relevant, but didn't explain the concepts well enough that I understood how to build a working solution. I've been scouring google but haven't found any information that describes exactly what's going on in such a way that I understand. Any direction to background concepts that may help me understand what's going on would be greatly appreciated.
Is it possible to get user input in a bash script that was executed from a pipe?
For example:
wget -q -O - http://myscript.sh | bash
And in the script:
read -p "Do some action (y/n): " __response
if [[ "$__response" =~ ^[Yy]$ ]]; then
echo "Performing some action ..."
fi
As I understand it, this doesn't work because read attempts to read the input from stdin and the bash script is currently "executing through that pipe" (i'm sure there is a more technical accurate way to describe what is occurring, but i don't know how).
I found a solution that recommended using:
read -t 1 __response </dev/tty
However, this does not work either.
Any light shed on the concepts I need to understand to make this work, or explanations of why it is not working or solutions would be greatly appreciated.
The tty solution works. Test it with this code, for example:
$ date | { read -p "Echo date? " r </dev/tty ; [ "$r" = "y" ] && cat || echo OK ; }
Echo date? y
Sat Apr 12 10:51:16 PDT 2014
$ date | { read -p "Echo date? " r </dev/tty ; [ "$r" = "y" ] && cat || echo OK ; }
Echo date? n
OK
The prompt from read appears on the terminal and read waits for a response before deciding to echo the date or not.
What I wrote above differs from the line below in two key aspects:
read -t 1 __response </dev/tty
First, the option -t 1 gives read a timeout of one second. Secondly, this command does not provide a prompt. The combination of these two probably means that, even though read was briefly asking for input, you didn't know it.
The main reason why this is not working is, as the OP validly indicated,
The | <pipe> which is used, sends the standard output from the first command as standard input to the second command. In this case, the first command is
wget -q -O - http://myscript.sh
which passes a downloaded script via the pipe to its interpreter bash
The read statement in the script uses the same standard input to obtain its value.
So this is where it collapses because read is not awaiting input from you but takes it from its own script. Example:
$ cat - <<EOF | bash
> set -x
> read p
> somecommand
> echo \$p
> EOF
+ read p
+ echo somecommand
somecommand
In this example, I used a here-document which is piped to bash. The script enables debugging using set -x to show what is happening. As you see, somecommand is never executed but actually read by read and stored in the variable p which is then outputted by echo (note, the $ has been escaped to avoid the substitution in the here-document).
So how can we get this to work then?
First of, never pipe to an interpreter such as {ba,k,z,c,tc,}sh. It is ugly and should be avoided, even though it feels the natural thing to do. The better thing to do is to use any of its options:
bash -c string: If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.
$ bash -c "$(command you want to pipe)"
This also works for zsh, csh, tcsh, ksh, sh and probably a lot of others.

Bash user input while not match variable loop

I'm trying to get a user input to loop until the input/name is unique (not contained in output/variable).
I've tried to do something like this, which I thought would have worked:
read -p "$QlabelName" input
while [[ "$input" == "$(/usr/sbin/networksetup -listallnetworkservices |grep "$input")" ]]; do
read -p "Name already in use, please enter a unique name:" input
done
I've also tried putting the $(/usr/sbin/networksetup -listallnetworkservices |grep "$input") bit into a variable itself and then using the condition [[ "$input" == "GREPVARIABLE" ]] without success.
Original user input menu, without loop (working):
labelName=NJDC
QlabelName=$(echo Please enter the name of connection to be displayed from within the GUI [$labelName]: )
read -p "$QlabelName" input
labelName="${input:-$labelName}"
echo "The connection name will be set to: '$labelName'"
I've tried a variety of solutions from SO, Unix, ServerFault, etc with no success. I've tried if, while, until, !=, ==, =~ as well with no success.
I've confirmed with simple debug echo's at each step that variables contain the data, but the loop is not working.
EDIT (solution, in context to the question, thanks to #LinuxDisciple's answer):
labelName=NJDC
QlabelName=$(echo Please enter the name of connection to be displayed from within the GUI [$labelName]: )
read -p "$QlabelName" input
while /usr/sbin/networksetup -listallnetworkservices |grep -q "^${input}$"; do
read -p "Name already in use, please enter a unique name:" input
done
labelName="${input:-$labelName}"
echo "The connection name will be set to: '$labelName'"
This was important to me to keep default variable values for labelName and output the correct information to the user.
read -p "$QlabelName" input
while /usr/sbin/networksetup -listallnetworkservices |grep -q "^${input}$"; do
read -p "Name already in use, please enter a unique name:" input
done
grep's return code is good enough for while, and since we don't want to actually see the output, we can use -q to suppress it. You can also run it without -q to see what grep actually found until you're satisfied that it's running correctly.
For further debuggability, I would pipe the output to cat -A. You can echo your variable value in the while-loop and just add |cat -A immediately after the done and it should show all the characters:
read -p "$QlabelName" input
while /usr/sbin/networksetup -listallnetworkservices |grep -q "^${input}$"; do
read -p "Name already in use, please enter a unique name:" input
echo "Input was:'$input'"
done |cat -A

Read from active tty in %post-Script during rpm-package installation

I've built my own rpm-packages. After installation, I need some informations from the user via keyboard input, so I've created an post-Script which is working properly if I start it from bash.
In the first step, the script is asking you if a value is correct. If you press Nn you were ask to enter the new one. Here is one example:
while [[ ! ($REPLY =~ ^[NnJjYy]$) ]]
do
read -p "This is just an example, pleaser answer with NnJjYy only" -n 1 -r < $(tty)
if [[ $REPLY =~ ^[Nn]$ ]]
then
printf "\nValue="
read HOST < $(tty)
fi
echo
done
This part is working properly if I run it directly. If I put it on the %post-Part of my SPEC-File, it will run as an endless loop with the errormsg "Mehrdeutige Umlenkung" which should mean "amibigious redirect" in english.
I think the problem is caused by the "$(tty)" of the read command, because if I change this to my active tty (e.g. /dev/pts/0) it's working, but I would like to have it universal.
Do you have any ideas how I could do this?

shell script : check variable and then execute interactive mode

I am writing a utility that can run in command line or interactive mode. In the code, I'd like to check if interactive flag is set and then echo the questions to the User for reading the input. However, for ever question , i dont want to check interactive flag with if condition. In bash script, is there a more efficient way to achieve this ?
Any pointers are greatly appreciated!
Thank you
Something like this maybe?
#! /bin/bash
function interactive {
shift
while read line; do
something with $line
done
}
getopts 'i' option
[[ $option = 'i' ]] && interactive "$#"
Note that this isn't the best style if you have multiple options. In that case use while getopts and shift using argument index.
If you want to tell if the shell is in "interactive mode", as defined by the shell, then you can use something like:
case $- in
*i*) # Interactive
;;
*) # Non-interactive
;;
esac
This, however, is probably not what you want. Shell scripts, for example, are, by default, "non-interactive".
If you want to know if you can ask the user a question, then you are more interested in finding out if stdin is connected to a terminal. In that case, you can use the -t test on file descriptor zero (which is standard input):
if [ -t 0 ]
then
# Interactive: ask user
read -p "Enter a color: " color
read -p "Enter a number: " number
else
# Non-interactive: assign defaults
color="Red"
number=3
fi
echo "color=$color and number=$number"
If there is the possibility that your script might be run remotely over, say, ssh, then a slightly more complicated test is needed:
if [ -t "$fd" ] || [ -p /dev/stdin ]
then
echo interactive
else
echo non-interactive
fi

Resources