Xterm: How can I direct input from one terminal tab to another? - linux

As I am a beginner coder, I apologize in advance for improper terminology.
This is the main script which calls the script ping.sh in a new tab.
#!/bin/bash
echo "The script is running!"
rm ping.txt
echo "Enter your desired IP address:"
read ADDRESS
osascript -e 'tell application "System Events" to tell application "Terminal"
do script "./ping.sh"
end tell'
echo "The script has ended!"
exit 0;
So, as I said the script ping.sh is called now. It goes like this.
#!/bin/bash
echo "Welcome to the new tab!"
ping -c 3 $ADDRESS > ping.txt
exit 0
The problem I have is that the read input from the first tab isn't recognizable in the second tab. Is there a way to solve this? I am probably missing a linking constructor or something like that. Please help!

I have no idea what osascript is, or how it works, but it might be helpful to know that shell scripts can access command line arguments with the special variables $1, $2, $3, etc.
This means you can rewrite your ping.sh script like so:
#!/bin/bash
echo "Welcome to the new tab!"
ping -c 3 "$1" > ping.txt
exit 0
And then call it like so:
#!/bin/bash
echo "Enter your desired IP address:"
read ADDRESS
./ping.sh "$ADDRESS"
Otherwise, to make sure subsequent commands have access to the same environment variables, you have to export them. From help export:
export: export [-fn] [name[=value] ...] or export -p
Set export attribute for shell variables.
Marks each NAME for automatic export to the environment of subsequently
executed commands. If VALUE is supplied, assign VALUE before exporting.
To make your original ping.sh work you could do the following:
#!/bin/bash
echo "Enter your desired IP address:"
read ADDRESS
export ADDRESS
./ping.sh

Related

Linux bash script - For loops issues

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

Set local environmental variable within a bash script

I'm trying to set an environmental variable that will persist once the script has finished running. It can go away after I end an ssh session.
Sample bash script:
# User picks an option
1) export dogs = cool
2) export dogs = not_cool
Running the script as source script.sh doesn't work since it kicks me out of my shell when ran and also requires the interactive menu so it won't work. Basically I want the user to be able to pick an option to switch between environmental variables in their shell. Is that even possible?
Source:
#!/bin/bash
set -x
show_menu(){
NORMAL=`echo "\033[m"`
MENU=`echo "\033[36m"` #Blue
NUMBER=`echo "\033[33m"` #yellow
FGRED=`echo "\033[41m"`
RED_TEXT=`echo "\033[31m"`
ENTER_LINE=`echo "\033[33m"`
echo -e "${MENU}*********************************************${NORMAL}"
echo -e "${MENU}**${NUMBER} 1)${MENU} Option 1 ${NORMAL}"
echo -e "${MENU}**${NUMBER} 2)${MENU} Option 2 ${NORMAL}"
echo -e "${MENU}*********************************************${NORMAL}"
echo -e "${ENTER_LINE}Please enter a menu option and enter or ${RED_TEXT}enter to exit. ${NORMAL}"
read opt
}
function option_picked() {
COLOR='\033[01;31m' # bold red
RESET='\033[00;00m' # normal white
MESSAGE=${#:-"${RESET}Error: No message passed"}
echo -e "${COLOR}${MESSAGE}${RESET}"
}
clear
show_menu
while [ opt != '' ]
do
if [[ $opt = "" ]]; then
exit;
else
case $opt in
1) clear;
option_picked "Option 1";
export dogs=cool
show_menu;
;;
2) clear;
option_picked "Option 2";
export dogs=not_cool
show_menu;
;;
x)exit;
;;
\n)exit;
;;
*)clear;
option_picked "Pick an option from the menu";
show_menu;
;;
esac
fi
done
The problem here is that . ./script.sh or source ./script.sh cannot run an interactive menu style script like this one. No way that I'm aware of to set local environmental variables from a bash script like I am trying to do here.
Redirect your normal echo's for user interaction to stderr (>&2)
echo the value that you want to have in your parent's environment to stdout (>&1)
if you changed your script that way you can call it like:
ENV_VAR=$( /path/to/your_script arg1 arg2 arg3 arg_whatever )
and now you have "exported" a variable to the "parent"
Try running your script with "./myscript.sh" which will use the current shell without invoking the new shell (still i doubt the hash bang might invokes the new shell).
Have a look here
Can also be solved with ~/.bashrc. The required environments can added in this file. If you need new shell with your own environment, you invoke "bash" with "bash --rcfile ".

read command is not taking input from the terminal

I dont know if it is weird that read is not taking the input from the terminal.
The configure script, which is used in source code making process, should ask the user to give the input to select the type of Database either MYSQL or ORACLE(below is the code).
MYSQLLIBPATH="/usr/lib/mysql"
echo "Enter DataBase-Type 1-ORACLE, 2-MySQL (default MySQL):"
read in
echo $? >> /tmp/error.log
if test -z "$in" -o "$in" = "2"
then
DATABASE=-DDB_MYSQL
if true; then
MYSQL_TRUE=
MYSQL_FALSE='#'
else
MYSQL_TRUE='#'
MYSQL_FALSE=
fi
echo "Enter Mysql Library Path: (eg: $MYSQLLIBPATH (default))"
read in
echo $? >> /tmp/error.log
if test -n "$in"
then
MYSQLLIBPATH=`echo $in`
fi
echo "Mysql Lib path is $MYSQLLIBPATH"
else
if false; then
MYSQL_TRUE=
MYSQL_FALSE='#'
else
MYSQL_TRUE='#'
MYSQL_FALSE=
fi
DATABASE=-DDB_ORACLE
LD_PATH=
fi
But, the read command is not asking for the user input. Its failing to take the input from the stdin.
When I checked the status of the command in the error.log it was showing
1
1
Could anyone tell why read is failing to take the input from the stdin.
Are there any builtin variable which can block read taking the input?
Most likely read executes with standard input redirected from a file that has reached EOF. If the above is not the whole of your configure code, check that there are no input redirections. Could the code above be a part of a function which was invoked with some input from a pipe or a file? Otherwise check how configure is executed - are there any redirections?
Otherwise, the universal advice applies: try simplifying and stripping down your code until it is obvious what's happening.
BTW, it is not a good idea to make configure interactive, if you want to have your program packaged for a distribution - it's not easy to control execution of interactive programs. Consider adding support for supplying parameters through command line options.

Echo text that is user-editable

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.

Bash script to capture input, run commands, and print to file

I am trying to do a homework assignment and it is very confusing. I am not sure if the professor's example is in Perl or bash, since it has no header. Basically, I just need help with the meat of the problem: capturing the input and outputting it. Here is the assignment:
In the session, provide a command prompt that includes the working directory, e.g.,
$./logger/home/it244/it244/hw8$
Accept user’s commands, execute them, and display the output on the screen.
During the session, create a temporary file “PID.cmd” (PID is the process ID) to store the command history in the following format (index: command):
1: ls
2: ls -l
If the script is aborted by CTRL+C (signal 2), output a message “aborted by ctrl+c”.
When you quit the logging session (either by “exit” or CTRL+C),
a. Delete the temporary file
b. Print out the total number of the commands in the session and the numbers of successful/failed commands (according to the exit status).
Here is my code so far (which did not go well, I would not try to run it):
#!/bin/sh
trap 'exit 1' 2
trap 'ctrl-c' 2
echo $(pwd)
while true
do
read -p command
echo "$command:" $command >> PID.cmd
done
Currently when I run this script I get
command read: 10: arg count
What is causing that?
======UPDATE=========
Ok I made some progress not quite working all the way it doesnt like my bashtrap or incremental index
#!/bin/sh
index=0
trap bashtrap INT
bashtrap(){
echo "CTRL+C aborting bash script"
}
echo "starting to log"
while :
do
read -p "command:" inputline
if [ $inputline="exit" ]
then
echo "Aborting with Exit"
break
else
echo "$index: $inputline" > output
$inputline 2>&1 | tee output
(( index++ ))
fi
done
This can be achieved in bash or perl or others.
Some hints to get you started in bash :
question 1 : command prompt /logger/home/it244/it244/hw8
1) make sure of the prompt format in the user .bashrc setup file: see PS1 data for debian-like distros.
2) cd into that directory within you bash script.
question 2 : run the user command
1) get the user input
read -p "command : " input_cmd
2) run the user command to STDOUT
bash -c "$input_cmd"
3) Track the user input command exit code
echo $?
Should exit with "0" if everything worked fine (you can also find exit codes in the command man pages).
3) Track the command PID if the exit code is Ok
echo $$ >> /tmp/pid_Ok
But take care the question is to keep the user command input, not the PID itself as shown here.
4) trap on exit
see man trap as you misunderstood the use of this : you may create a function called on the catched exit or CTRL/C signals.
5) increment the index in your while loop (on the exit code condition)
index=0
while ...
do
...
((index++))
done
I guess you have enough to start your home work.
Since the example posted used sh, I'll use that in my reply. You need to break down each requirement into its specific lines of supporting code. For example, in order to "provide a command prompt that includes the working directory" you need to actually print the current working directory as the prompt string for the read command, not by setting the $PS variable. This leads to a read command that looks like:
read -p "`pwd -P`\$ " _command
(I use leading underscores for private variables - just a matter of style.)
Similarly, the requirement to do several things on either a trap or a normal exit suggests a function should be created which could then either be called by the trap or to exit the loop based on user input. If you wanted to pretty-print the exit message, you might also wrap it in echo commands and it might look like this:
_cleanup() {
rm -f $_LOG
echo
echo $0 ended with $_success successful commands and $_fail unsuccessful commands.
echo
exit 0
}
So after analyzing each of the requirements, you'd need a few counters and a little bit of glue code such as a while loop to wrap them in. The result might look like this:
#/usr/bin/sh
# Define a function to call on exit
_cleanup() {
# Remove the log file as per specification #5a
rm -f $_LOG
# Display success/fail counts as per specification #5b
echo
echo $0 ended with $_success successful commands and $_fail unsuccessful commands.
echo
exit 0
}
# Where are we? Get absolute path of $0
_abs_path=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
# Set the log file name based on the path & PID
# Keep this constant so the log file doesn't wander
# around with the user if they enter a cd command
_LOG=${_abs_path}/$$.cmd
# Print ctrl+c msg per specification #4
# Then run the cleanup function
trap "echo aborted by ctrl+c;_cleanup" 2
# Initialize counters
_line=0
_fail=0
_success=0
while true
do
# Count lines to support required logging format per specification #3
((_line++))
# Set prompt per specification #1 and read command
read -p "`pwd -P`\$ " _command
# Echo command to log file as per specification #3
echo "$_line: $_command" >>$_LOG
# Arrange to exit on user input with value 'exit' as per specification #5
if [[ "$_command" == "exit" ]]
then
_cleanup
fi
# Execute whatever command was entered as per specification #2
eval $_command
# Capture the success/fail counts to support specification #5b
_status=$?
if [ $_status -eq 0 ]
then
((_success++))
else
((_fail++))
fi
done

Resources