Is it possible to output text to a shell window, via bash script, that is user-editable? I essentially want to pre-fill certain information and give the user the ability to edit it if it's wrong.
For instance, if I were to write in a script:
echo -n "Enter your name: Anthony"
while read user_input
do
# do stuff with $user_input
done
How can I allow the user to inline edit the word Anthony only (aka, don't allow backspacing past the A in Anthony), and how can I store the value into a variable once the RETURN key is pressed?
EDIT
I'm looking for something similar to the -i option of read (see answer posted here), but this is only available on bash 4+. Is there an alternative for bash 3?
I needed similar setup recently so what I did was
$ cat a.sh
function input {
python -c '
import sys,readline
readline.set_startup_hook(lambda: readline.insert_text(sys.argv[2]))
sys.stderr.write(raw_input(sys.argv[1]))
' "$#" 3>&1 1>&2 2>&3
}
A=$( input 'question: ' default )
echo "A='$A'"
$ ./a.sh
question: default
A='default'
Well, it's not actually bash, but it made the job done.
Related
I'm working on a bash script (my_script) in which I call many scripts, they all together automate a work flow.
But when I call one particular (ksh/bash) script (master_script) there are many inputs and checks taken (not arguments) in it.
It is slowing down the whole of the automation, as every time I have to super wise it and enter the values manually.
I have no option to modify or make a new script (work constraints)
Every time the questions are same. I am trying to take all the answers before executing master_script except one answer(whose value depends on the execution) and then feed it to the master_script at the correct time.
Is there a way we can pass the value to the master_script, during its execution from within my_script.? ./master_script<< EOF .. EOF will not help as I have to enter one answer myself.
The below is just an example and my creation, but depicts what exactly is my requirement.
Example code
my_script
#! /bin/bash
echo "Proceeding...."
#calling master_script
/master_script $arg1 $arg2
echo "Completed.."
echo "Executing other scripts"
/other_scripts"
Execution
$ sh ./my_script
Proceeding....
Started master_script..
Press Enter to Proceed MY_INPUT
Enter username to add (eg.user123) MY_UNAME
Enter preferred uid (eg.1234) MY_UID
Do you want to bla bla..(Y/n) MY_INPUT
Please select among the following
1.option1
2.Option2
Selection: MY_SELECTION
Please choose which extension to use
1.ext1
2.ext2
3.ext3
4.ext4
Do you want to bla bla 2..(Y/n) MY_INPUT
Ended master script
Completed..
Executing other scripts
Requirement
#! /bin/bash
echo "Proceeding...."
# get values for master script
read -p "Proceed(Y/n):" proceed1
read -p "Uname:" uname
read -p "Uid:" uid
read -p "bla bla (Y/n):" bla1
read -p "Selection(1/2):" selection1
read -p "bla bla 2(Y/n):" bla2
#calling master_script
./master_script $arg1 $arg2 {all_inputs}
#Silent Execution of master_script until choosing execution...
Please choose which extension to use
1. ext1
2. ext2
3. ext3
4. ext4
#Silent Execution of master_script after choosing ext and continue with other scripts
./other_scripts
echo "Completed.."
I've read about expect/send combination, but I'm unable to comprehend
how to use it. Any inputs will be greatly helpful
EDIT
I am also not sure about ./master_script<< EOF ... EOF as I have to enter one
answer in the middle of execution myself.
There is a solution using here documents and redirecting the input:
./master_script "$arg1" "$arg2" << ENDINPUT
$proceed1
$uname
$uid
$bla1
$selection1
ENDINPUT
Remark 1: the final ENDINPUT must start the line, don't indent! See Man bash
Remark 2: some scripts or programs check if the input comes from an actual terminal (calling isatty()), for instance when typing a password. It is still possible to automate the entries, but it is much more tricky.
I'm trying to write a bash script that search and replace a specific
user input saved in config.sh using sed. This does work; however it
only works partially as shown below.
config.sh
#!/bin/bash
#
#UserName to be deleted
delUserName=""
#Source
delUserSrc=/Users/"$delUserName"
#Destination
delUserDest=/Users/John/BackUp/"$delUserName"/"$delUserName".zip
main.sh
#!/bin/bash
#
source scripts/config.sh
echo -e "\nEnter user you wish to delete: \c"
read -r UserName
sed -i '' -e "s/delUserName=.*/delUserName=$UserName/g" scripts/config.sh
echo -e "delUserName: $delUserName"
echo -e "delUserSrc: $delUserSrc"
echo -e "delUserDest: $delUserDest"
output1:
Enter user you wish to delete: Test
delUserName:
delUserSrc:/Users/
delUserDest:/Users/John/BackUp/ / .zip
output2:
Enter user you wish to delete: Test1
delUserName:Test
delUserSrc:/Users/Test
delUserDest:/Users/John/BackUp/Test/Test.zip
output3:
Enter user you wish to delete: Test1
delUserName:Test1
delUserSrc:/Users/Test1
delUserDest:/Users/John/BackUp/Test1/Test1.zip
expected output1:
Enter user you wish to delete: Test
delUserName:Test
delUserSrc:/Users/Test
delUserDest:/Users/John/BackUp/Test/Test.zip
expected output2:
Enter user you wish to delete: Test1
delUserName:Test1
delUserSrc:/Users/Test1
delUserDest:/Users/John/BackUp/Test1/Test1.zip
The script lags. sed instantaneously changed the value for $delUserName BUT The proper values for $delUserName, $delUserSrc, and $delUserDest only echo on the 2nd run. The scripts run well when all variables are in main.sh except i have to do it this way. Save the user input into $UserName. Any idea why the values don't show when run the 1st time?
Thanks
Here is what I think is happening.
The sed command replaces text in files. It does not modify the value of variables in memory. These values are assigned when you source config.sh.
So right after your sed line, you need to put this line :
source scripts/config.sh
It is the same line as above in your script. This is required there also so that your newly replaced values will be loaded in the variables so that you can display them. Once the new values are loaded in memory, then the echo statements will be able to expand the variables to that new value.
I've created a really simple bash script that runs a few commands.
one of these commands needs user input during runtime. i.e it asks the user "do you want to blah blah blah?", I want to simply send an enter keypress to this so that the script will be completely automated.
I won't have to wait for the input or anything during runtime, its enough to just send the keypress and the input buffer will handle the rest.
echo -ne '\n' | <yourfinecommandhere>
or taking advantage of the implicit newline that echo generates (thanks Marcin)
echo | <yourfinecommandhere>
You can just use yes.
# yes "" | someCommand
You might find the yes command useful.
See man yes
Here is sample usage using expect:
#!/usr/bin/expect
set timeout 360
spawn my_command # Replace with your command.
expect "Do you want to continue?" { send "\r" }
Check: man expect for further information.
You could make use of expect (man expect comes with examples).
I know this is old but hopefully, someone will find this helpful.
If you have multiple user inputs that need to be handled you can use process substitution and use echo as a 'file' for cat with whatever is needed to handle the first input like this:
# cat ignores stdin if it has a file to look at
cat <(echo "selection here") | command
and then you can handle subsequent inputs by piping the yes command with the answer:
cat <(echo "selection here") | yes 'y' | command
I'm working on a bash script that will add users in a batch process. This code goes as follows:
#!/bin/bash
# A script that creates users.
echo "This is a script to create new users on this system."
echo "How many users do you want to add?"
read am
echo " "
for i in {0..$am..1}
do
echo "Enter a username below:"
read usern
sudo useradd $usern
sudo passwd $usern
echo " "
echo "User $am '$usern' added."
done
In this case, I wanted to make 4 users. I went through and entered the username "callum3" and set the password as "1234" for ease of login. Once I input everything (correctly, may I add) the terminal window displays the following.
User 4 'callum3' added.
This shows that my for loop isn't actually working, when I can see nothing wrong with it. I have tried using a while loop with no luck there either.
Am I making a rookie mistake here or is there something deeper going on?
Although I suspected it, for a better understanding on what could be wrong with your script I pasted it in shellcheck.net. That the problem is in the line:
for i in {0..$am..1}
Bash doesn't support variables in brace range expansions. That is, you cannot use a variable in an expression like {..}.
Instead, use seq. With seq $var you get a sequence from 1 (default) to $var:
for i in $(seq "$am")
I feel like I'm missing something in that nobody has suggested an arithmetic for loop:
for ((i=0; i<am; i++)); do
…
done
This has the particular benefit in bash of being both readable and not requiring a subshell.
You can use:
for i in `seq 0 $((am-1))`
do
...
done
Sequence will start from 0 and end at $am-1
I want to create a bash script that is simular to a programming interpreter like mongo, node, redis-cli, mysql, etc.
I want to be able to use a command like test and it behave like the examples above.
thomas#workstation:~$ test
>
How do I make a command that behaves like this? What is this called?
I want to be able to take the content and turn it into a variable.
thomas#workstation:~$ test
> hello world
hello world
thomas#workstation:~$
I only want to take one "entry" after enter is pressed once I want to be able to process the string "hello world" in the code, like echo it.
What is this called? How do I make one using BASH?
I think "read" is what you are looking for, isn't it?
here is a link with some examples: http://bash.cyberciti.biz/guide/Getting_User_Input_Via_Keyboard
so you can do stuff like this:
read -p "Enter your name : " name
echo "Hi, $name. Let us be friends!"
I'm sorry this doesn't answer you directly, but it might be worth it to look into using a more fully capable programming language such as Python, Ruby, or Perl for a task like this. In Python you can use the raw_input() function.
user_command = raw_input('> ')
would yield your prompt.
First, do not name your script test. That generates too much confusion. Whatever you call it, you can do many things:
#!/bin/sh
printf '> '
read line
echo "$line"
If your shell supports it:
#!/bin/sh
read -p '> ' line
echo "$line"
or
#!/bin/sh
printf '> '
sed 1q # This will print the input. To store in in a variable: a=$( sed 1q )
[spatel#tux ~]$ read a
Hello World!!!!!
[spatel#tux ~]$ echo $a
Hello World!!!!!
Key word that might be useful here is REPL (Read–eval–print loop) used primarily for programming languages or coding environments. Your browsers console is a great example of a REPL.
Node allows you use their REPL to build interactive apps.