Hi I have a question about a process. This is what I get when I run the line:
ls -l /proc/3502/exe
If I run this line:
echo "$(xargs -0 < /proc/${pids[0]}/cmdline)"
I get an output like: /bin/bash ./sleeper.sh 10
Does that mean the procces that was actually run is /bin/bash and everything after that was only passed to it as arguments(Procces: /bin/bash args that it got: ./sleeper.sh 10)?? Because I know the last part is the name of a script and an argument passed to it.
Does that mean the procces that was actually run is /bin/bash and everything after that was only passed to it as arguments(Procces: /bin/bash args that it got: ./sleeper.sh 10)??
That's exactly the case. When you run a script like this: ./script, the program loader parses the script, looking for a shebang that will tell it how to run that script. Shebangs are needed to differentiate, say, a Python script from a Bash script, or from a Perl script. Such scripts are actually executed by their respective interpreters, which are usually /bin/python, /bin/bash, /bin/perl, and that's why you see it listed as /bin/bash ./sleeper 10 rather than ./sleeper.sh 10.
For example, say ./script looks like this:
#!/bin/sh
echo yo
Running it with ./script will cause the system to spawn /bin/sh ./script. (Anecdote: because of how it works, some shebangs include also command line parameters on its own such as #!/usr/bin/perl -T, which will cause the system to spawn your script as /usr/bin/perl -T x).
As for why the script sees ./sleeper.sh 10 rather than /bin/bash ./sleeper.sh 10 - it's just how Bash (and other interpreters) works. The shebang expansion is visible to everyone, including Bash. Hence ps ux will show /bin/bash ./sleeper.sh 10. However, it would make little sense for your script to know exact specific combination of Bash flags and Bash path it was invoked with, so Bash strips these away and passes only relevant command line. Bash tries to make that command line consistent with general command line rules, meaning the first argument to your script will be usually the path to your script (caveats), and the rest of the arguments are the arguments passed to your script.
Seeing all of this in action
./test:
#!/bin/bash -i
echo $BASH_ARGV
Running it as ./test prints nothing. The process is spawned as /bin/bash -i ./test.
Running it as ./test x y prints x y. The process is spawned as /bin/bash -i ./test x y.
Suggestion
It's widely recommended to omit .sh, .py, .pl etc. extensions from executable files.
Related
I have a CLI which generates a bash script. How can I evaluate it immediatly without redirecting to a .sh file?
example is to change the following:
~: toolWhichGeneratesScript > tmp.sh
~: chmod +x tmp.sh
~: ./tmp.sh
to something like:
~: toolWhichGeneratesScript | evaluate
You can pass in commands to run with bash -c (or sh -c):
bash -c "$(toolWhichGeneratesScript)"
-c If the -c option is present, then commands
are read from the first non-option argument
command_string. If there are arguments
after the command_string, they are assigned
to the positional parameters, starting with
$0.
Unlike piping to the shell, this leaves stdin free for you to interact with prompts and programs the script runs.
The shell reads its script from standard input:
toolWhichGeneratesScript | sh
(In fact, an interactive shell does the same; it's standard input just happens to be a terminal.)
Note that you need to know which shell to use; if your tool outputs bash extensions, then you have to pipe it to bash. Also, if the generated script itself needs to read from standard input, you have a bit of a problem.
Try to do this : toolWhichGeneratesScript | bash
I'm using the 'at' command in order to create 3 directories, just a dumb bash script:
#!/bin/bash
for i in {1..3}
do
mkdir dir$i
done
Everything is ok if I execute that script directly on terminal, but when I use 'at' command as follows:
at -f g.sh 18:06
It only creates one directory named dir{1..3}, taking interval not as an interval but as a list with one element {1..3}. According to this I think my mistake is using bash script due to at executes commands using /bin/sh but I'm not sure.
Please tell me if I'm right and I would appreciate some alternative to my code since even it is useless I'm curious to know what's wrong with at and bash.
The #! line only affects what happens when you run a script as a program (e.g. using it as a command in the shell). When you use at, it's not being run as a program, it's simply used as the standard input to /bin/sh, so the shebang has no effect.
You could do:
echo './g.sh' | at 18:06
I have some shell scripts which I run in my Linux/AIX machine with bash profile. Now my bash profile is going to be remove, and I will have Korn shell (ksh) or the C shell (csh). How to verify whether my scripts will run fine in Korn shell (ksh) or C shell (csh), even after bash shell is removed. Also, is there any differnce in commonly used commands between bash and other (ksh, csh). Is there command to check, which shell is getting used while running the shell script.
First of all, this is not a problem, the default shell of your account is irrelevant. As long as bash is installed on the machine, you can use it to run your code. Either add a shebang line as the first line of your script:
#!/usr/bin/env bash
Or, explicitly run the script with bash:
$ /bin/bash /path/to/script.sh
As for the differences, yes there are many. A script written for bash will not run in csh, their syntax is completely different. It might run on ksh but that will depend on your script. Not all features of the two shells are the same. For example:
$ cat test.sh
var="foo";
echo $var;
$ bash ./test.sh
foo
$ ksh ./test.sh
foo
$ csh ./test.sh
var=foo: Command not found.
var: Undefined variable.
As you can see above, var=foo runs correctly in ksh (which is part of the bourne shell family) but fails for csh. Basically, think of each shell as its own programming language. You wouldn't expect the python interpreter to be able to run a perl program, why do you expect one shell to be able to run a script written for another?
OP writes bash is going to be removed.
If you really cannot get bash installed. start each script with #!/bin/ksh and check for syntax problems:
ksh -n migrated_script
When you use bash/linux specific things you need to address them:
AIX will be "missing" flags on commands like find (changed last hour...) and ksh itself is also different.
Do not try csh, that is completely different.
I have tried a lot but couldn't get the solution out of it. I have a simple script:
#! /bin/sh
o="12345"
a=o
b=${!a}
echo ${a}
echo ${b}
When executed like
$ . scp.sh
it produces the correct output with no errors, but when executed like:
$ ./scp.sh
it produces
./scp.sh: 4: ./scp.sh: Bad substitution
Any ideas why this is happening.
I was suggested to use bash mode and it works fine. But when I execute this same script through Python (changing the script header to bash), I am getting the same error.
I'm calling it from Python as:
import os
os.system(". ./scp.sh")
Try using:
#!/bin/bash
instead of
#! /bin/sh
The reason for this error is that two different shells are used in these cases.
$ . scp.sh command will use the current shell (bash) to execute the script (without forking a sub shell).
$ ./scp.sh command will use the shell specified in that hashbang line of your script. And in your case, it's either sh or dash.
The easiest way out of it is replacing the first line with #!/bin/bash (or whatever path bash is in).
I am looking at a tcsh script that has the following shebang line:
#!/bin/tcsh -fb
# then executes some commands
What does the -b do?
From the man page:
-b Forces a ''break'' from option processing, causing any further shell arguments to
be treated as non-option arguments. The remaining arguments will not be inter-
preted as shell options. This may be used to pass options to a shell script with-
out confusion or possible subterfuge. The shell will not run a set-user ID script
without this option.
But I don't really understand what it means...
An example would be great.
Thanks.
Say, for example, you have a script that is named --help and you want to execute it using tcsh:
tcsh --help
This will obviously not work. The -b forces tcsh to stop looking for arguments and treat the rest of the command line as file names or arguments to scripts. So, to run the above weirdly named script, you could do
tcsh -b --help