How do I programmatically execute a carriage return in bash? - bash

My main file is main.sh:
cd a_folder
echo "executing another script"
source anotherscript.sh
cd ..
#some other operations.
anotherscript.sh:
pause(){
read -p "$*"
}
echo "enter a number: "
read number
#some operation
pause "Press enter to continue..."
I wanted to skip the pause command. But when I do:
echo "/n" | source anotherscript.sh
It doesn't allow to enter the number. I want the "/n" to occur so that I allow the user to enter a number but skip the pause statement.
PS: can't do any changes in anotherscript.sh. All changes to be done in main.sh.

Try
echo | source anotherscript.sh

Your approach does not work, because the script to be sourced expectes two lines from stdin: First a line containing a number, then an empty line (which is doing the pause). Hence you would have to feed two lines, the number and the empty line, to the script. If you still want to get the number from your own stdin, you would have to use a read command before:
echo "executing another script"
echo "enter a number: "
read number
printf "$number\n\n" | source anotherscript.sh
But this still has some danger lurking: The source command is executed in a subshell; hence, any changes in the environment performed by anotherscript.sh won't be visible in your shell.
A workaround would be to be to put the number-reading logic outside of main.sh:
# This is script supermain.sh
echo "executing another script"
echo "enter a number: "
read number
printf "$number\n\n"|bash main.sh
where in main.sh, you simply keep your source anotherscript.sh without any piping.

As user1934428 comments, the bash pipeline causes the cascading
commands to be executed in subshells and the variable modifications
there are not reflected in the current process.
To change this behavior, you can set lastpipe with shopt builtin.
Then bash changes the job control so that the last command in the
pipeline is executed in the current shell (as tsch does).
Then would you please try:
main_sh
#!/bin/bash
shopt -s lastpipe # this changes the job control
read -p "enter a number: " x # ask for the number in main_sh instead
cd a_folder
echo "executing another script"
echo "$x" | source anotherscript.sh > /dev/null
# anotherscript.sh is executed in the current process
# unnecessary messages are redirected to /dev/null
cd ..
echo "you entered $number" # check the result
#some other operations.
which will properly print the value of number.
Alternatively you can also say as:
#!/bin/bash
read -p "enter a number: " x
cd a_folder
echo "executing another script"
source anotherscript.sh <<< "$x" > /dev/null
cd ..
echo "you entered $number"
#some other operations.

Related

Bash Scripting - User Input a Command

Very easy question but I really can't find this when I Google. Sorry!
I'm trying to write a script that runs a user's command that he or she enters but I can't run the command that the user enters.
#!/bin/bash
echo -e "Enter a Command: "
read $COMMAND
echo "Output: $COMMAND" # I can't figure how to implement and print the command
Enter a Command: ls
Output: folder1 folder2 folder3 test.txt)
All you need is to delete the dollar sign from the read command
#!/bin/bash
echo "Enter a Command: "
read COMMAND
echo "Output: $COMMAND"
Happy scripting!, please don't forget to marked as answered ;)
Use eval to execute a command from a variable.
Also, you don't put $ before the variable name in the read command. That's only used when you want to get the variable's value.
#!/bin/bash
echo -e "Enter a Command: "
read COMMAND
echo Output:
eval "$COMMAND"
DEMO
Thanks! This answered my question:
#!/bin/bash
echo -e "Enter a Command: "
read COMMAND
echo Output:
eval "$COMMAND"

Read from executable and write back response

I'm starting an executable with
./test
It will then write a text to stdout
static test: DYNAMIC_VAL
The static test is always the same but the value DYNAMIC_VAL changes.
I need to read DYNAMIC_VAL, process it and send back byte hex codes \x12\x34\x56 to the stdin depending on DYNAMIC_VAL.
./test is an executable and the stdin should be performed to the original invocation of test, otherwise the DYNAMIC_VAL would have changed with a new invocation.
Is there a simple way of doing this in bash?
If I'm understanding this question correctly, you want to read a line from your ./test process, and write data back to the same process and repeat until it produces something saying it's done (Or forever)?
One way is to use a coprocess.
Example:
$ cat test.sh
#!/bin/sh
echo "static test: foo"
read line
echo "static test: bar"
read line
echo "static test: done"
$ cat demo.sh
#!/usr/bin/env bash
coproc ./test.sh
while true; do
read -r -u "${COPROC[0]}" s t dynamic_val
case "$dynamic_val" in
"done")
echo "Exiting"
break;;
*)
echo "read $dynamic_val"
printf "\x12\x34\x56\n" >&"${COPROC[1]}";;
esac
done
$ ./demo.sh
read foo
read bar
Exiting

Read from .txt file containing executable commands to be executed w/ output of commands executed sent to another file

When I run my script, the .txt file is read, the executable commands are assigned to $eggs, then to execute the commands and redirect the output to a file I use echo $eggs>>eggsfile.txt but when I cat the file, I just see all the commands and not the execution output of those commands.
echo "Hi, $USER"
cd ~/mydata
echo -e "Please enter the name of commands file:/s"
read fname
if [ -z "$fname" ]
then
exit
fi
terminal=`tty`
exec < $fname #exec destroys current shell, opens up new shell process where FD0 (STDIN) input comes from file fname
count=1
while read line
do
echo $count.$line #count line numbers
count=`expr $count + 1`; eggs="${line#[[:digit:]]*}";
touch ~/mydata/eggsfile.txt; echo $eggs>>eggsfile.txt; echo "Reading eggsfile contents: $(cat eggsfile.txt)"
done
exec < $terminal
If you just want to execute the commands, and log the command name before each command, you can use 'sh -x'. You will get '+ command' before each command.
sh -x commands
+pwd
/home/user
+ date
Sat Apr 4 21:15:03 IDT 2020
If you want to build you own (custom formatting, etc), you will have to force execution of each command. Something like:
cd ~/mydata
count=0
while read line ; do
count=$((count+1))
echo "$count.$line"
eggs="${line#[[:digit:]]*}"
echo "$eggs" >> eggsfile.txt
# Execute the line.
($line) >> eggsfile.txt
done < $fname
Note that this approach uses local redirection for the while loop, avoiding having to revert the input back to the terminal.

Passing in parameter to bash script

I have this simple bash script:
#!/bin/sh
(echo "AUTH xxx xxx"
sleep 3
number=0161XXXXXXX
echo "ACTI $number"
sleep 3
echo "SET $number 1 S:$number#x.x.x.x"
sleep 3
echo "STAT $number"
sleep 3
echo "QUIT") | telnet xxx.xxx 777
I want to pass the number in as a parameter when I call the script, i.e.
bash number.sh 0161XXXXXXX
How can I do that?
Thanks
Use positional parameters. You could also directly use $1 instead storing in a variable.
#!/bin/sh
arg=$1
(echo "AUTH xxx xxx"
sleep 3
number=$arg
echo "ACTI $number"
sleep 3
echo "SET $number 1 S:$number#x.x.x.x"
sleep 3
echo "STAT $number"
sleep 3
echo "QUIT") | telnet xxx.xxx 777
From bash man page:
Arguments
If arguments remain after option processing, and neither the -c nor
the -s option has been supplied, the first argument is assumed to be
the name of a file containing shell commands. If bash is invoked in
this fashion, $0 is set to the name of the file, and the positional
parameters are set to the remaining arguments. Bash reads and executes
commands from this file, then exits. Bash's exit status is the exit
status of the last command executed in the script. If no commands are
executed, the exit status is 0. An attempt is first made to open the
file in the current directory, and, if no file is found, then the
shell searches the directories in PATH for the script.
So the first argument can be referred as $1, the second as $2 (until $9, if more you need to process it in other way such as using shift...)

Redirect to a file which is got from command line

I'm a beginner. :)
I'm trying to ask the name of file from prompt in a shell
and edit that file in another shell like this:
test.sh
echo "enter file name"
read word
sh test2.sh
test2.sh
read number
echo "$number" >> $word
I get an error
Test2.sh: line 1: $mAmbiguous redirect
Any suggestion?
If you want a variable from test.sh to be visible to its child processes, you need to export it. In your case, you would seem to want to export word. Perhaps a better approach would be for test2.sh to accept the destination file as a parameter instead, though.
test.sh
echo "enter file name"
read word
test2.sh "$word"
test2.sh
#!/bin/sh
: ${1?must have destination file name} # fail if missing
read number
echo "$number" >> "$1"

Resources