Bash Script: want to call a function that reads input - bash

I'm writing a script that calls on a function that reads for input in multiple lines. I want to pass parameters into the read, but I don't know if I can or how to.
aka how to get enter-grades to take my values as input instead of waiting for input at the prompts?
Inside my bash script
...
login="studentName"
echo "enter score:"
read score
echo "comments:"
read comments
enter-grades $hw #---> calls another function (dont know definition)
#
# i want to pass parameters into enter-grades for each read
echo "$login" #---> input to enter-grade's first read
echo "$score $comments" #---> input to enter-grade's second read
echo "." #---> input to enter-grade's third read
outside my bash script
#calling enter-grades
> enter-grades hw2
Entering grades for assignment hw2.
Reading previous scores for hw2...
Done.
Enter grades one at a time. End with a login of '.'
Login: [READS INPUT HERE]
Grade and comments: [READS INPUT HERE]
Login: [READS INPUT HERE]

Assuming that enter-grades does not read directly from the terminal, just supply the information on that program's standard input:
login="studentName"
read -p "enter score: " score
read -p "comments: " comments
then, group your echo commands together, and pass all that into the program:
{
echo "$login"
echo "$score $comments"
echo "."
} | enter-grades "$hw"
or, succinctly
printf "%s\n" "$login" "$score $comments" "." | enter-grades "$hw"
Quote all your variables.
Or, with a here-doc
enter-grades "$hw" <<END
$login
$score $comments
.
END

Related

How to assign stdin arguments to variables in BASH from Pipe

What I'm trying:
I'm trying to assign args to a variable if it is from Pipe
Expected:
What should I do inside my script to assign the arguments to variables so that they look like this?
if [ -p /dev/stdin ]; then
option1="one"
option2="two"
option3="three"
echo "$option1" "$option2" "$option3"
else
echo "no input"
fi
Input: echo one two three | ./myscript
Output: one two three
Question Update:
I need all the arguments presented before the |(pipe) as just string input to my script.
It should not check for existence or execute the binary(here the binary is echo) present before the |(pipe).
Input: echo one two three | ./myscript
Output: echo one two
The words one, two, three in echo one two three | ./myscript are arguments of echo; but to ./myscript they are only input, not arguments.
Reading "arguments" from stdin
To read each word into its own variable use
if [ -p /dev/stdin ]; then
read -r option1 option2 option3
echo "$option1" "$option2" "$option3"
else
echo "no input"
fi
If you want to allow an arbitrary number of words, use an array.
read -ra myArray reads all words from a single line into an array.
mapfile -t myArray reads all lines into an array.
read -rd '' -a myArray reads all words from all lines into an array.
To access the words in the array, use ${myArray[0]}, ${myArray[1]}, ..., ${myArray[${#myArray[#]}-1]}.
Using actual arguments
Instead of parsing stdin it might be better to use actual arguments. To do so, execute your script like ./myscript one two three. Then access the arguments using positional parameters:
if [ $# = 0 ]; then
echo "no arguments"
else
echo "The arguments are $1 $2 $3 ..."
fi
For an arbitrary number of arguments check out shift and $#.
You should probably simply use xargs instead. But what you ask isn't hard to do per se.
if [ -p /dev/stdin ]; then
read -r option1 option2 option3
echo "$option1" "$option2" "$option3"
else
echo "no input"
fi
With xargs, this would look like
option1=$1
option2=$2
option3=$3
and then you'd just run it with
echo first second third |
xargs ./yourscript

Writing an equivalent of Python's input function in bash

I am trying to write a simple equivalent of Python's input function in Bash.
An example in a Python script would be something like this:
s = input('Please input something: ')
I imagine the call to a Bash equivalent would look like this:
s=$(input "Please input something: ")
This is the implementation that I wrote:
function input {
# $1 is the prompt passed as an argument; in my above example,
# it would be 'Please input something: '
printf "%s" "$1"
read in
echo "${in}"
return 0
}
With the call s=$(input "Please enter something: "), the prompt never prints; instead, the Bash script simply waits for user input without ever displaying the text. Pressing Enter, that is, giving no input, sets s to the prompt itself. What seems to be happening is s captures the output from the line printf "%s" "$1", then reads input which it also echoed back. I have also tried explicitly directing the prompt to stdout with printf "%s" "$1" >&1, but to no avail.
How can I print the prompt first, then capture input and echo it back to the calling function?
You're in luck. It already exists in the form of read -p.
read -p 'Please input something: ' s
To be safe, it's a good idea to use IFS= and -r as well. IFS= makes sure leading and trailing whitespace are retained. -r preserves backslashes so \n isn't interpreted as a newline, or \\ turned into \.
IFS= read -rp 'Please input something: ' s
As to why your function doesn't work, it's because the prompt is being printed to stdout, which is captured. Print to stderr to get it to show up.
input() {
printf "%s" "$1" >&2
read in
printf '%s\n' "$in"
}
A careful scripter will use printf '%s\n' in place of echo. If the user types -n or -e you want those printed, not interpreted as options.

How to make search, enter text and replace a line in bash?

I've been trying to write a bash code (experimenting) where bash will ask (Enter Text) and the user will enter a certain text lets say (I am new) and the text (I am new) will be moved to a line called User=I am new.
So, here is a cfg file named xyz.cfg
User
Name
Address
Country
and here is the bash script called test and with only echo $Input > $file the bash replace the whole file with the entered text but I want to keep the config as it is and add the Enter Text: value to the line User but this doesn't help, the code below,
#! /bin/sh
file=/root/xyz.cfg
echo "Enter text:"
read Input
echo $Input > $file **(confused here)** **(it replaces the whole cfg)**
Another line I thought of is here, but it doesn't work. I am not good with these so I hope it's solved; I tried searching the web with zero luck.
(doesn't work)
#! /bin/sh
file=/root/xyz.cfg
echo "Enter text:"
read Input
echo $Input > sed '/User/a' xyz.cfg
(doesn't work)
#! /bin/sh
file=/root/xyz.cfg
echo "Enter text:"
read Input
echo $Input > sed '/User/a' $file
Edit:
When a someone is asked for Enter Text: while running the bash script ./test and the someone typed Entered Text from bash promot the entered $Input (Entered Text from bash promot) should move to xyz.cfg and add the line to the Variable User:
Finally, the xyz.cfg should look like
User: Entered Text from bash prompt
Name
Address
Country
Before it looked like this,
User:
Name
Address
Country
Edit2: This GIF might explain what I need.
This should do the trick:
#!/bin/bash
FILE=/tmp/test.cfg
echo -n "Enter text: "
read INPUT
sed -i "s/User:/& $INPUT/" "$FILE"
This uses sed to do an in-place search / replace (-i) which appends the entered text after the first occurence of User: on each line within $FILE.
& refers to the matched portion of the text - it's essentially saying "replace <thing> with <thing> <entered text>."
If you need to prompt for text each time a matching User: line is encountered, you can use the following approach:
#!/bin/bash
FILE=/tmp/test.cfg
ORIGINAL=$(cat "$FILE")
truncate -s 0 "$FILE"
while read LINE; do
if `grep -q 'User:' <<< "$LINE"`; then
echo -n "Enter text: "
read INPUT < /dev/tty
sed "s/User:/& $INPUT/" <<< "$LINE" >> "$FILE"
else
echo "$LINE" >> "$FILE"
fi
done <<< "$ORIGINAL"
This second approach does the following:
Reads the entire file contents into a variable;
Removes the existing file contents;
Loops over each line of the original content, and:
If the line contains User:, prompt for and append the custom text;
Append the line to the file.

How to loop script till user input is empty?

I am trying to make my script to repeat till the user leaves the block question empty. I just got the loop to run, but I can not find a way to make it possible to stop it when block is empty.
I hope some one can help me!!
#!/bin/tcsh -f
#
set word="start"
until ($word !=""); do
#First ask for Compound and Block Name.
echo -n "please enter block name: "
read block
echo -n "please enter compound name: "
read compound
#Now coping template with new name
#
cp Template $block
#
for line in `cat $block`;do
echo $line | sed -e "s/test1/${block}/g" -e "s/test2/${compound}/g" >>./tmp124.txt
done
mv ./tmp124.txt $block
done
Do you want to use bash or csh? You are using bash syntax but tagged your question csh and call tcsh in the first line of your code.
To answer your question, here are examples of how to iterate on standard input until some input is empty:
For tcsh:
#!/bin/tcsh
while ( 1 )
set word = "$<"
if ( "$word" == "" ) then
break
endif
# rest of code...
end
For bash:
#!/bin/bash
while read word; do
if [ -z $word ]; then
break
fi
# rest of code...
done
Use "Until do" loop,
Eg :
For session variable i am assigning default value, Then entering loop. User can pass any value on each prompt when the value is empty, Loop will Terminate and exit the script.
session="Mysession"
until [$session -eq $null]
do
echo $session
echo "Leave Blank to Terminate session"
read -p "Enter session name : " session
done
echo "Exiting.."

How do I read user input into a variable in Bash?

How do I read user input into a variable in Bash?
fullname=""
# Now, read user input into the variable `fullname`.
Use read -p:
# fullname="USER INPUT"
read -p "Enter fullname: " fullname
# user="USER INPUT"
read -p "Enter user: " user
If you like to get the user's confirmation:
read -p "Continue? (Y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1
You should also quote your variables to prevent pathname expansion and word splitting with spaces:
# passwd "$user"
# mkdir "$home"
# chown "$user:$group" "$home"
Yep, you'll want to do something like this:
echo -n "Enter Fullname: "
read fullname
Another option would be to have them supply this information on the command line. Getopts is your best bet there.
Using getopts in bash shell script to get long and short command line options
Try this
#/bin/bash
read -p "Enter a word: " word
echo "You entered $word"
Also you can try zenity !
user=$(zenity --entry --text 'Please enter the username:') || exit 1
https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html
One line is read from the standard input, or from the file descriptor
fd supplied as an argument to the -u option, split into words as
described above in Word Splitting, and the first word is assigned to
the first name, the second word to the second name, and so on. If
there are more words than names, the remaining words and their
intervening delimiters are assigned to the last name.
echo "bash is awesome." | (read var1 var2; echo -e "Var1: $var1 \nVar2: $var2")
bash will be var1
is awesome will be var2
echo -e enable interpretation of backslash escapes from ubuntu manual.
so the full code can be:
echo -n "Enter Fullname: "
read fullname
echo "your full name is $fullname."
echo -n "test type more than 2 word: "
read var1 var2; echo -e
read var1 var2; echo -e "Var1: $var1 \nVar2: $var2")
Maximally portable (bash, zsh, ...):
printf "%s" "Enter fullname: "
read fullname
This is the most portable way to read with prompt. Methods such as read -p and echo -n are more likely to fail depending on the shell.

Resources