Run shell command from child shell - shell

I have a Unix shell script test.sh. Within the script i would like to invoke another shell and then execute the rest of the commands in the shell script from the child shell and exit
To make it clear:
test.sh
#! /bin/bash
/bin/bash /* create child shell */
<shell-command1>
<shell-command2>
......
<shell-commandN>
exit 0
What my intention is to run the shell-commands1 to shell-commandN from the child shell. Kindly tell me how to do this

You can setup in a group, like.
#!/bin/bash
(
Command1
Command2
etc..
)
subshell() {
echo "this is also within a subshell"
}
subshell
( and ) creates a subshell in which you run a group of commands, otherwise a simple function will do. I don't know if ( and ) is POSIX compatible.
Update: If I understand your comment correctly, you want to be using -c option with bash, like.
/bin/bash -c "Command1 && Command2...." &

From http://tldp.org/LDP/abs/html/subshells.html here is an example:
#!/bin/bash
# subshell-test.sh
(
# Inside parentheses, and therefore a subshell . . .
while [ 1 ] # Endless loop.
do
echo "Subshell running . . ."
done
)
# Script will run forever,
#+ or at least until terminated by a Ctl-C.
exit $? # End of script (but will never get here).

Related

How to execute a command in a different shell?

I have a bash script that opens up a shell called salome shell and it should execute a command called as_run in that shell. The thing is that after entering the salome shell it doesn't execute the command until I exit the salome shell. This is the code that i got:
#!/bin/bash
cd /opt/salome/appli_V2018.0.1_public
./salome shell
eval "as_run /home/students/gbroilo/Desktop/Script/Template_1_2/exportSalome"
What should I do in order to execute the command in the salome shell?
Might be this is what you want:
# call salome shell with commands in a specified script file
cd /opt/salome/appli_V2018.0.1_public
./salome shell <"/home/students/gbroilo/Desktop/Script/Template_1_2/exportSalome"
Or might be this is what you want:
# pipe a command as_run... to salome shell
cd /opt/salome/appli_V2018.0.1_public
echo "as_run /home/students/gbroilo/Desktop/Script/Template_1_2/exportSalome" | ./salome shell
Anyway, you have to read the salome guide about how salome shell call it's script.
Most shells implement a way to pass the commands as parameters, e.g.
dash -c 'x=1 ; echo $x'
You'll need to consult your shell's manual to see if it's possible.
You can also try sending the commands to the standard input of the shell:
echo 'set x = 1 ; echo $x' | tcsh
Using a HERE doc might be a bit more readable in case of complex commands:
tcsh << 'TCSH'
set x = 1
echo $x
TCSH

Bash: ( commands ) | command

I stumbled upon Zenity, a command-line based GUI today. I noticed the there was some syntax of the form ( commands ) | command. Could anyone shed some light on what this is and where I can read more about it?
I found the below script within the docs
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
--title="Update System Logs" \
--text="Scanning mail logs..." \
--percentage=0
The parentheses are delimiting a subshell, which means the commands inside the parens are run in a separate process, and interpreted by a separate instance of the bash interpreter. In this case, it appears they are using a subshell just to group together all the echo and sleep commands so that they can then pipe the combined output of the entire group of commands through zenity. Which makes sense given that the goal in this example is to simulate a progress bar.
You can read more about subshells here: http://tldp.org/LDP/abs/html/subshells.html
The parentheses create a subshell, with all the implications that it has for the current shell.
The subshell cannot change the environment of the parent shell; sometimes, you want a subshell so that you can, say, quickly cd to a different directory without affecting the working directory for the rest of the script
The subshell has a single standard input and a single standard output stream; this is frequently a reason to start a subshell
The parent shell waits while the subshell completes the commands (unless you run it in the background)
If it helps,, think of ( foo; bar ) as a quick way to say sh -c 'foo; bar'.
A related piece of syntax is the brace, which runs a compound command in the current shell, not a subshell.
test -f file.rc || { echo "$0: file.rc not found -- aborting" >&2; exit 127; }
The exit in particular causes the current shell to exit with a failure exit code, while a subshell which exits does not directly affect the rest of the parent shell script.
(Weirdly, POSIX requires a statement terminator before the closing brace, but not before the closing parenthesis.)

Entering cshell from bash

I have a bash script and need to run some commands in cshell inside it.
#!/bin/bash
echo entering_to_cshell
csh
echo in_cshell
exit
echo exited_from_cshell
Why doesn't this script run as expected? It only prints entering_to_cshell and it doesn't exit from cshell.
By using
csh
you start a new subshell where your script isn't executed. That's why none of your following commands are executed. Your script waits for this subshell to end which, as you noted, never happens.
Try
csh -c "echo in_cshell"
This way you don't create a new subshell which isn't impacted by your script.
By simply calling csh in your script, you're starting an interactive csh subshell. You'll notice that once you quit from the csh session, your script will then continue to with the subsequent echo and quiting on exit.
To pass a series of commands to csh from you bash script, one approach would be to use the Here Document syntax to redirect commands to csh.
#!/bin/bash
echo entering_to_cshell
csh <<EOF
echo in_cshell
exit
EOF
echo exited_from_cshell
The lines between the EOF entries will be treated as a script that is interpreted by csh.

How to include nohup inside a bash script?

I have a large script called mandacalc which I want to always run with the nohup command. If I call it from the command line as:
nohup mandacalc &
everything runs swiftly. But, if I try to include nohup inside my command, so I don't need to type it everytime I execute it, I get an error message.
So far I tried these options:
nohup (
command1
....
commandn
exit 0
)
and also:
nohup bash -c "
command1
....
commandn
exit 0
" # and also with single quotes.
So far I only get error messages complaining about the implementation of the nohup command, or about other quotes used inside the script.
cheers.
Try putting this at the beginning of your script:
#!/bin/bash
case "$1" in
-d|--daemon)
$0 < /dev/null &> /dev/null & disown
exit 0
;;
*)
;;
esac
# do stuff here
If you now start your script with --daemon as an argument, it will restart itself detached from your current shell.
You can still run your script "in the foreground" by starting it without this option.
Just put trap '' HUP on the beggining of your script.
Also if it creates child process someCommand& you will have to change them to nohup someCommand& to work properly... I have been researching this for a long time and only the combination of these two (the trap and nohup) works on my specific script where xterm closes too fast.
Create an alias of the same name in your bash (or preferred shell) startup file:
alias mandacalc="nohup mandacalc &"
Why don't you just make a script containing nohup ./original_script ?
There is a nice answer here: http://compgroups.net/comp.unix.shell/can-a-script-nohup-itself/498135
#!/bin/bash
### make sure that the script is called with `nohup nice ...`
if [ "$1" != "calling_myself" ]
then
# this script has *not* been called recursively by itself
datestamp=$(date +%F | tr -d -)
nohup_out=nohup-$datestamp.out
nohup nice "$0" "calling_myself" "$#" > $nohup_out &
sleep 1
tail -f $nohup_out
exit
else
# this script has been called recursively by itself
shift # remove the termination condition flag in $1
fi
### the rest of the script goes here
. . . . .
the best way to handle this is to use $()
nohup $( command1, command2 ...) &
nohup is expecting one command and in that way You're able to execute multiple commands with one nohup

Determining whether shell script was executed "sourcing" it

Is it possible for a shell script to test whether it was executed through source? That is, for example,
$ source myscript.sh
$ ./myscript.sh
Can myscript.sh distinguish from these different shell environments?
I think, what Sam wants to do may be not possible.
To what degree a half-baken workaround is possible, depends on...
...the default shell of users, and
...which alternative shells they are allowed to use.
If I understand Sam's requirement correctly, he wants to have a 'script',
myscript, that is...
...not directly executable via invoking it by its name myscript
(i.e. that has chmod a-x);
...not indirectly executable for users by invoking sh myscript or
invoking bash myscript
...only running its contained functions and commands if invoked by
sourcing it: . myscript
The first things to consider are these
Invoking a script directly by its name (myscript) requires a first line in
the script like #!/bin/bash or similar. This will directly determine which
installed instance of the bash executable (or symlink) will be invoked to run
the script's content. This will be a new shell process. It requires the
scriptfile itself to have the executable flag set.
Running a script by invoking a shell binary with the script's (path+)name as
an argument (sh myscript), is the same as '1.' -- except that the
executable flag does not need to be set, and said first line with the
hashbang isn't required either. The only thing needed is that the invoking
user needs read access to the scriptfile.
Invoking a script by sourcing its filename (. myscript) is very much the
same as '1.' -- exept that it isn't a new shell that is invoked. All the
script's commands are executed in the current shell, using its environment
(and also "polluting" its environment with any (new) variables it may set or
change. (Usually this is a very dangerous thing to do: but here it could be
used to execute exit $RETURNVALUE under certain conditions....)
For '1.':
Easy to achieve: chmod a-x myscript will prevent myscript from being
directly executable. But this will not fullfill requirements '2.' and '3.'.
For '2.' and '3.':
Much harder to achieve. Invokations by sh myscript require reading
privileges for the file. So an obvious way out would seem to chmod a-r
myscript. However, this will also dis-allow '3.': you will not be able to
source the script either.
So what about writting the script in a way that uses a Bashism? A Bashism is a
specific way to do something which other shells do not understand: using
specific variables, commands etc. This could be used inside the script to
discover this condition and "do something" about it (like "display warning.txt",
"mailto admin" etc.). But there is no way in hell that this will prevent sh or
bash or any other shell from reading and trying to execute all the following
commands/lines written into the script unless you kill the shell by invoking
exit.
Examples: in Bash, the environment seen by the script knows of $BASH,
$BASH_ARGV, $BASH_COMMAND, $BASH_SUBSHELL, BASH_EXECUTION_STRING... . If
invoked by sh (also if sourced inside a sh), the executing shell will see
all these $BASH_* as empty environment variables. Again, this could be used
inside the script to discover this condition and "do something"... but not
prevent the following commands from being invoked!
I'm now assuming that...
...the script is using #!/bin/bash as its first line,
...users have set Bash as their shell and are invoking commands in the
following table from Bash and it is their login shell,
...sh is available and it is a symlink to bash or dash.
This will mean the following invokations are possible, with the listed values
for environment variables
vars+invok's | ./scriptname | sh scriptname | bash scriptname | . scriptname
---------------+--------------+---------------+-----------------+-------------
$0 | ./scriptname | ./scriptname | ./scriptname | -bash
$SHLVL | 2 | 1 | 2 | 1
$SHELLOPTS | braceexpand: | (empty) | braceexpand:.. | braceexpand:
$BASH | /bin/bash | (empty) | /bin/bash | /bin/bash
$BASH_ARGV | (empty) | (empty) | (empty) | scriptname
$BASH_SUBSHELL | 0 | (empty) | 0 | 0
$SHELL | /bin/bash | /bin/bash | /bin/bash | /bin/bash
$OPTARG | (empty) | (empty) | (emtpy) | (emtpy)
Now you could put a logic into your text script:
If $0 is not equal to -bash, then do an exit $SOMERETURNVALUE.
In case the script was called via sh myscript or bash myscript, then it will
exit the calling shell. In case it was run in the current shell, it will
continue to run. (Warning: in case the script has any other exit statements,
your current shell will be 'killed'...)
So put into your non-executable myscript.txt near its beginning something like
this may do something close to your goal:
echo BASH=$BASH
test x${BASH} = x/bin/bash && echo "$? : FINE.... You're using 'bash ...'"
test x${BASH} = x/bin/bash || echo "$? : RATS !!! -- You're not using BASH and I will kick you out!"
test x${BASH} = x/bin/bash || exit 42
test x"${0}" = x"-bash" && echo "$? : FINE.... You've sourced me, and I'm your login shell."
test x"${0}" = x"-bash" || echo "$? : RATS !!! -- You've not sourced me (or I'm not your bash login shell) and I will kick you out!"
test x"${0}" = x"-bash" || exit 33
This may or may not be what the asker wanted but, on a similar situation, I wanted a script to indicate that it is meant to be sourced and not directly run.
To achieve this effect my script reads:
#!/bin/echo Should be run as: source
export SOMEPATH="/some/path/on/my/system"
echo "Your environment has been set up"
So when I run it either as a command or sourced I get:
$ ./myscript.sh
Should be run as: source ./myscript.sh
$ source ./myscript.sh
Your environment has been set up
You can of course fool the script by running it as sh ./myscript.sh, but at least it gives the correct expected behaviour on 2 out of 3 cases.
This is what I was looking for:
[[ ${BASH_SOURCE[0]} = $0 ]] && main "$#"
I cannot add comment yet (stackexchange policies) so I add my own answer:
This one may works regardless if we do:
bash scriptname
scriptname
./scriptname.
on both bash and mksh.
if [ "${0##/*}" == scriptname ] # if the current name is our script
then
echo run
else
echo sourced
fi
If you have a non-altering file path for regular users, then:
if [ "$(/bin/readlink -f "$0")" = "$KNOWN_PATH_OF_THIS_FILE" ]; then
# the file was executed
else
# the file was sourced
fi
(it can also easily be loosened to only check for the filename or whatever).
But your users need to have read permission to be able to source the file, so absolutely nothing can stop them from doing what they want with the file. But it might help them out to not use it in the wrong way.
This solution is not dependent on Bashisms.
Yes it is possible. In general you can do the following:
#! /bin/bash
sourced () {
echo Sourced
}
executed () {
echo Executed
}
if [[ ${0##*/} == -* ]]; then
sourced
else
executed $#
fi
Giving the following output:
$ ./myscript
Executed
$ . ./myscript
Sourced
Based on Kurt Pfeifle’s answer, this works for me
if [ $SHLVL = 1 ]
then
echo 'script was sourced'
fi
Example
Since all of our machines have history, I did this:
check_script_call=$(history |tail -1|grep myscript.sh )
if [ -z "$check_script_call" ];then
echo "This file should be called as a source."
echo "Please, try again this way:"
echo "$ source /path/to/myscript.sh"
exit 1
fi
Everytime you run a script (without source), your shell creates a new env without history.
If you want to care about performance you can try this:
if ! history |tail -1|grep set_vars ;then
echo -e "This file should be called as a source.\n"
echo "Please, try again this way:"
echo -e "$ source /path/to/set_vars\n"
exit 1
fi
PS: I think Kurt's answer is much more complete but I think this could help.
In the first case, $0 will be "myscript.sh". In the second case, it will be "./myscript". But, in general, there's no way to tell source was used.
If you tell us what you're trying to do, instead of how you want to do it, a better answer might be forthcoming.

Resources