What is the difference between "bash -i myscript.sh" vs "bash myscript.sh"? - shell

According to bash man page, it says -i is for interactive mode of shell.
I tried example code to find out what -i option does.
interactive.sh is script that needs user input, which means interactive script.
The default bash option is non-interactive mode.
But the interactive.sh runs without any problem with non-interactive mode.
It also runs well with interactive mode. It confuses me.
What is the exact usage of -i option in bash?
What is the difference between interactive and non-interactive mode in shell?
$cat interactive.sh
#!/bin/bash
echo 'Your name ?'
read name
echo "Your name is $name"
$ bash interactive.sh
Your name ?
ABC
Your name is ABC
$ bash -i interactive.sh
Your name ?
DEF
Your name is DEF

With bash -i script you are running interactive non-login shell.q
What is the exact usage of -i option in bash?
From man bash:
-i If the -i option is present, the shell is interactive.
What is the difference between interactive and non-interactive mode in shell?
There are some differences. Look at man bash | grep -i -C5 interactive | less:
An interactive shell is one started without non-option arguments (unless -s is specified) and without the -c option whose standard input and er‐
ror are both connected to terminals (as determined by isatty(3)), or one started with the -i option. PS1 is set and $- includes i if bash is
interactive, allowing a shell script or a startup file to test this state.
When an interactive login shell exits, or a non-interactive login shell executes the exit builtin command, bash reads and executes commands from
the file ~/.bash_logout, if it exists.
When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists. This may
be inhibited by using the --norc option. The --rcfile file option will force bash to read and execute commands from file instead of ~/.bashrc.
[...]
When bash is interactive, in the absence of any traps, it ignores SIGTERM (so that kill 0 does not kill an interactive shell), and SIGINT is
caught and handled (so that the wait builtin is interruptible). In all cases, bash ignores SIGQUIT. If job control is in effect, bash ignores
SIGTTIN, SIGTTOU, and SIGTSTP.
etc. For example bash -i -c 'echo $PS1'.

Related

detect default interactive shell doesn't work on shell script

I use zsh as the default shell, I run echo $0 and get -zsh on terminal, but the following code can't detect default interactive shell
#!/usr/bin/env bash
if [ -n "$ZSH_VERSION" ]; then
echo "zsh"
elif [ -n "$BASH_VERSION" ]; then
echo "bash"
else
echo "others"
fi
The detect result is always bash, why? Thank you.
Your code works for detecting the current shell. But scripts run in their own shell, independently from the interactive shell. Your script file always runs in bash due to its shebang. Without the shebang, the calling shell decides how to run the script (if at all).
Detecting the parent shell
To detect the shell that called your script, try
#!/usr/bin/env bash
ps -p $PPID -o comm=
When you run an interactive zsh and execute this file you should get zsh as output.
Detecting the default shell
Your question's title is about detecting the default interactive shell. To do so, you cannot check any processes, because even if your default shell is X you can always use Y. Instead, look at the file where the default is stored:
grep "^$USER:" /etc/passwd | cut -d: -f7
The standard way to do this is with the SHELL environment variable:
echo "Your default shell is $SHELL"
This is defined in the POSIX standard, section 8.3, "Other Environment Variables":
SHELL
This variable shall represent a pathname of the user's preferred command language interpreter. If this interpreter does not conform to the Shell Command Language in XCU Shell Command Language, utilities may behave differently from those described in POSIX.1-2017.

Calling rsync in bash from Windows cmd

I am trying to run rsync from a batch file. The command is
SET CMD="rsync -P -rptz --delete -e 'ssh -i /root/.ssh/CERTIFICATE.pem' SOURCE_ADDRESS /mnt/c/Users/MYNAME/IdeaProjects/PROJECT/SUBFOLDER/SUBFOLDER/SUBFOLDER/SUBFOLDER/LASTFOLDER"
bash %CMD%
This works fine if I run the command after typing bash, but when I run the command from cmd with the bash precursor it says No such file or directory.
Additionally, when playing around and trying to debug bash ends up hanging... i.e. if I open bash I get no prompt, just a blinking cursor.
Any help is appreciated.
To run a command with bash you need to use the -c option
bash -c "%CMD%"
Without it the first non-option parameter will be treated as a *.sh shell script, which rsync isn't and will cause an error
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.
Note that the cmd in Windows is not DOS even though they have a few similar commands. The rest are vastly different

qsub is executing my bash script in csh despite shebang

I want to submit a bash script to my university's Sungrid computing cluster to run an executable in a loop. When I log in to the server, I'm in bash:
$ echo $SHELL
/bin/bash
And I include a bash shebang at the top of the script that I pass to qsub:
$ cat shell_sub
#!/bin/bash
#$ -N bSS_s13
#$ -o logs/bSS_s13.log
#$ -j y
#$ -cwd
echo $SHELL > shell.txt
But when I submit the above script:
qsub shell_sub
It instead executes in csh:
$ cat shell.txt
/bin/csh
How can I force qsub to execute my script with bash instead of csh?
Most likely your queue is configured with shell_start_mode as posix_compliant and the defined shell is listed as /bin/csh (which is the default). To check this:
$ qconf -sq <name-of-queue> | grep shell
shell /bin/bash
shell_start_mode unix_behavior
If you don't know the name of your queue, it's probably all.q.
If shell_start_mode is posix_compliant, then the shebang line is ignored and the job (if it's not submitted as binary: -b y) is started with the shell defined by the shell setting.
Why? From the man page: "POSIX does not consider first script line comments such a ‘#!/bin/csh’ as being significant. The POSIX standard for batch queuing systems (P1003.2d) therefore requires a compliant queuing system to ignore such lines but to use user specified or configured default command interpreters instead."
If shell_start_mode is unix_behavior, then the shebang line is used to determine the shell for the job.
You can ask your administrator to consider changing the queue settings.
You can set the shell for a submitted job (at least in Torque) using -S.
For example: qsub shell_sub -S /bin/bash

Running command as login shell without starting a new shell?

I'm trying to see what the output of a command would be if I were in a login shell, without having to go into a login shell. I've tried several variations of
zsh --login -c "alias"
But none of my aliases get shown; are --login and -c incompatible?
To test the difference between zsh --login -c "alias" and a normal login shell, you can/should add the -x option to see what the shell is up to.
When I run zsh -x --login -c "alias", then it processes /etc/zprofile.
When I run zsh -x --login, then it processes /etc/zprofile and /etc/zshrc.
I don't normally use zsh, so I don't have any personalized profile or start up file for it, but it seems plausible that it might look for (but, in my case, not find) ~/.zprofile and ~/.zshrc too.
I created trivial versions of those files:
$ echo "echo in .zprofile" > ~/.zprofile
$ echo "echo in .zshrc" > ~/.zshrc
and sure enough, they're processed. Further, the -c command with --login processed the .zprofile but did not process the .zshrc file.
Thus, using -c "alias" after the --login suppresses the processing of /etc/zshrc and ~/.zshrc. If you want those executed even so, you need to use something like:
zsh --login -c "[ -f /etc/zshrc ] && . /etc/zshrc; [ -f ~/.zshrc ] && . ~/.zshrc; alias"
Using -x to debug login processing is often informative.
It's nice that modern shells provide a command line option to induce login processing. I still have a program (which I don't use any more) that runs a login shell the old-fashioned way, by adding a - before the shell name in argv[0]. Thus, running -ksh would trigger login processing; the login program would run the login shell with the - at the start.

Bash script "read" not pausing for user input when executed from SSH shell

I'm new to Bash scripting, so please be gentle.
I'm connected to a Ubuntu server via SSH (PuTTY) and when I run this command, I expect the bash script that downloads and executes to allow user input and then echo that input. It seems to just write out the echo label for the input request and terminate.
wget -O - https://raw.github.com/aaronhancock/pub/master/bash/readtest.sh | bash
Any clue what I might be doing wrong?
UPDATE: This bash command does exactly what I wanted
bash <(wget -q -O - https://raw.github.com/aaronhancock/pub/master/bash/readtest.sh)
Jonathan already mentioned: bash takes its stdin from the pipe.
And therefore you cannot pipe the script into bash when you want to interactively input something. But you could use the process substitution feature of bash (assumed your login shell is a bash):
bash <(wget -O - https://raw.github.com/aaronhancock/pub/master/bash/readtest.sh)
Bash is taking stdin from the pipe, not from the terminal. So you can't pipe a script to bash and still use the "read" command for user input.
Notice that you have the same problem if you save the script to a local file and pipe it to bash:
less readtest.sh | bash
I found this also works and helps keep the data in the current scope.
eval "wget -q -O - https://raw.github.com/aaronhancock/pub/master/bash/readtest.sh"

Resources