at command strange behaviour - linux

This is the first time i am playing with the at command in linux and notice something strange. Say i create this test file:
#!/bin/bash
count=1
echo "count is $count"
then i issue
at -f /full/path/to/myscript.sh -v 13:00 -m
and wait for it to run. Then in my mail, the value of count variable is nothing. What could be wrong?
To: root#localhost.localdomain
Status: R
count is
&

Are you sure your commands are being run by bash, and not some other interpreter like csh? I don't think the shebang line has any effect in an at job -- the commands are simply piped into whichever shell is specified via the SHELL environment variable.

Related

Self-defined bash command works in terminal but not in script

I have two scripts:
fail_def.sh:
#!/bin/bash -eu
function fail() {
echo -e "$(error "$#")"
exit 1
}
bla.sh:
#!/bin/bash -eu
fail "test"
After source fail_def.sh, I can use the fail command without any problems in the terminal. However, when I call bla.sh, I always get line 2: fail: command not found.
It doesn't matter whether I call it via ./bla.sh or bash bla.sh or bash ./bla.sh, the error remains.
Adding source fail_def.sh to the beginning of bla.sh solves the problem, but I'd like to avoid that.
I'm working on an Ubuntu docker container running on a Mac, in case that is relevant.
I tried to google that problem and found some similar problems, but most of them seem to be connected to either not sourcing the file or mixing up different shell implementations, neither of which seems to be the case here.
What do I have to do to get the fail command to work inside the script?
It is expected!
The shell runs the script run with an she-bang separator always as a separate process and hence on a different shell namespace. The new shell in which your script runs does not have the function source'd.
For debugging such information, add a line echo $BASHPID which prints the process id of the current bash process on the bla.sh script after the line #!/bin/bash -eu and a test result produced
$ echo $BASHPID
11700
$ bash bla.sh
6788
fail.sh: line 3: fail: command not found
They scripts you have run on separate process where the imported functions are not shared between. One of the ways would be to your own error handling on the second script and by source-ing the second script. On the second script
$ cat fail.sh
echo $BASHPID
set -e
fail "test"
set +e
Now running it
$ source fail.sh
11700
11700
bash: error: command not found
which is obvious as error is not a shell built-in which is available. Observe the process id's same on the above case.

What does it mean if a procces runs like this?

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.

Wrong BASH-Variable return from a bash script

I'd like to check the value of $HISTFILE (or any similar BASH-Variable) by a bash script. On the command console 'echo $HISTFILE' is the way I normally go, but from inside a bash script, which only includes:
#!/bin/bash
echo $HISTFILE
gives an empty line instead of showing $HOME/$USER/.bash_history (or similar return values). My questions are:
What is the reason for doing so (since I never had such trouble using bash scripts) and
how can I check the value of BASH-Variables like $HISTFILE from inside a bash script?
Many thanks in advance. Cheers, M.
HISTFILE is only set in interactive shells; scripts run in non-interactive shells. Compare
$ bash -c 'echo $HISTFILE' # non-interactive, no output
$ bash -ic 'echo $HISTFILE' # interactive, produces output
/home/me/.bash_history
However, forcing the script to run in an interactive shell will also cause your .bashrc file to be sourced, which may or may not be desirable.

bash is not executed 'at -f foo.sh' command, even with #!/bin/bash shebang

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

Bad substitution error in bash script

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).

Resources