How to create file with instruction of commands? - linux

I have a file name myFirstFile that contains certain commands.
But I am not able to excecute them.
If I want to execute this as a program, which code should be implemented?

If you want to execute your program, it should start with:
#!/bin/sh
It's the generic script file "header". It indicates that the script is a shell script (if it's bash script you should have #!/bin/bash, etc.). If you want to execute it, you should call chmod +x ./myFirstFile to give privileges to call it as program, and then you can start your script normally: ./myFirstFile.

Make this file executable* and give it *.sh extention like:
"myFirstFile.sh"
Than run it from terminal (or crontab - it can do things for you when you sleep :) ) like:
cd directory/you/have/that/file
sh ./myFirstFile.sh
*Im not shure that making it executable is the most secure thing you can do. All my sh scripts are and I never digged into this issue, so make sure its cool
Also make sure you have "#!/bin/bash" in first line - sometimes it helps (dont know why, Google it)
edit: for example my script for starting Minecraf server looks like this
start.sh
#!/bin/bash
BINDIR=$(dirname "$(readlink -fn "$0")")
cd "$BINDIR"
while true
do
java -Xmx3584M -jar craftbukkit.jar
echo -e 'If you want to completely stop the server process now, press ctrl-$
echo "Rebooting in:"
for i in {5..1}
do
echo "$i..."
sleep 1
done
echo 'Restarting now!'
done

You have to make the file executable:
chmod +x myFirstFile
Then you can execute the commands in it:
./myFirstFile

Related

Bash: Only allow script to run by being called from another script

We have two bash scripts to start up an application. The first (Start-App.sh) one sets up the environment and the second (startup.sh) is from a 3rd party that we are trying not to heavily edit. If someone runs the second script before the first the application does not come up correctly.
Is there a way to ensure that the startup.sh can only be called from the Start-App.sh script?
They are both in the same directory and run via bash on Red Hat Linux.
Is there a way to ensure that the startup.sh can only be called from the Start-App.sh script?
Ensure? No. And even less so without editing startup.sh at all. But you can get fairly close.
Below are three suggestions − you can either use one of them, or any combination of them.
The simplest, and probably the best, way is to add a single line at the top of startup.sh:
[ -z $CALLED_FROM_START_APP ] && { echo "Not called from Start-App.sh"; exit 42; }
And then call it from Start-App.sh like so:
export CALLED_FROM_START_APP=yes
sh startup.sh
of course, you can set this environment variable from the shell yourself, so it won't actually ensure anything, but I hope your engineering staff is mature enough not to do this.
You can also remove the execute permissions from startup.sh:
$ chmod a-x startup.sh
This will not prevent people from using sh startup.sh, so there is a very small guarantee here; but it might prevent auto-completion oopsies, and it will mark the file as "not intended to be executed" − if I see a directory with only one executable .sh file, I'll try and run that one, and not one of the others.
Lastly, you could perhaps rename the startup.sh script; for example, you could rename it to do_not_run, or "hide" it by renaming it to .startup. This probably won't interfere with the operation of this script (although I can't check this).
TL;DR:
[ $(basename "$0") = "Start-App.sh" ] || exit
Explanation
As with all other solutions presented it's not 100% bulletproof but this covers most common instances I've come across for preventing accidentally running a script directly as opposed to calling it from another script.
Unlike other approaches presented, this approach:
doesn't rely on manually set file names for each included/sourced script (i.e. is resilient to file name changes)
behaves consistently across all major *nix distros that ship with bash
introduces no unnecessary environment variables
isn't tied to a single parent script
prevents running the script through calling bash explicitly (e.g. bash myscript.sh)
The basic idea is having something like this at the top of your script:
[ $(basename "$0") = $(basename "$BASH_SOURCE") ] && exit
$0 returns the name of the script at the beginning of the execution chain
$BASH_SOURCE will always point to the file the currently executing code resides in (or empty if no file e.g. piping text directly to bash)
basename returns only the main file name without any directory information (e.g. basename "/user/foo/example.sh" will return example.sh). This is important so you don't get false negatives from comparing example.sh and ./example.sh for example.
To adapt this to only allow running when sourced from one specific file as in your question and provide a helpful error message to the end user, you could use:
[ $(basename "$0") = "Start-App.sh" ] || echo "[ERROR] To start MyApplication please run ./Start-App.sh" && exit
As mentioned from the start of the answer, this is not intended as a serious security measure of any kind, but I'm guessing that's not what you're looking for anyway.
You can make startup.sh non-executable by typing chmod -x startup.sh. That way the user would not be able to run it simply by typing ./startup.sh.
Then from Start-App.sh, call your script by explicitly invoking the shell:
sh ./startup.sh arg1 arg2 ...
or
bash ./startup.sh arg1 arg2 ...
You can check which shell it's supposed to run in by inspecting the first line of startup.sh, it should look like:
#!/bin/bash
You can set environment variable in your first script and before running second script check if that environment variable is set properly.
Another alternative is checking the parent process and finding the calling script. This also needs adding some code to the second script.
For example, in the called script, you can check the exit status of this and terminate.
ps $PPID | tail -1 | awk '$NF!~/parent/{exit 1}'
As others have pointed out, the short answer is "no", although you can play with permissions all day but this is still not bulletproof. Since you said you don't mind editing (just not heavily editing) the second script, the best way to accomplish this would be something along the lines of:
1) in the parent/first script, export an environment variable with its PID. This becomes the parent PID. For example,
# bash store parent pid
export FIRST_SCRIPT_PID = $$
2) then very briefly, in the second script, check to see if the calling PID matches the known acceptable parent PID. For example,
# confirm calling pid
if [ $PPID != $FIRST_SCRIPT_PID ] ; then
exit 0
fi
Check out these links here and here for reference.
To recap: the most direct way to do this is adding at least a minimal line or two to the second script, which hopefully doesn't count as "heavily editing".
You can create a script, let's call it check-if-my-env-set containing
#! /bin/bash
source Start-App.sh
exec /bin/bash $#
and replace the shebang (see this) on startup.sh by that script
#! /abs/path/to/check-if-my-env-set
#! /bin/bash
...
then, every time you run startup.sh it will ensure the environment is set correctly.
To the best of my knowledge, there is no way to do this in a way that it would be impossible to get around it.
However, you could stop most attempts by using permissions.
Change the owner of the startup.sh file:
sudo chown app_specific_user startup.sh
Make startup.sh only executable by the owner:
chmod u+x startup.sh
Run startup.sh as the app_specific_user from Start-App.sh:
sudo -u app_specific_user ./startup.sh

How to Start a Bash Script with Fewest Keystrokes

To fire a shell script from the command line, instead typing this at a Linux/Unix command line:
~$ <shell> tale.sh
In my case, using bash:
~$ bash tale.sh
How do you setup profile/defaults/scripts so that the command will run with just:
~$ tale
I know this can be different for different shells. I need the answer for bash.
This is the whole listing for ~/tale.sh:
#! /bin/bash
tail -f ~/lp/_logs/error.log
That file, ~/lp/_logs/error.log, is a PHP error log.
First, you need to rename your script:
mv tale.sh tale
Then, there may be two additional steps:
1) Set the executable bit on your script:
chmod +x tale
2) Make sure your script is in your PATH. For example, you could place it in your bin directory (assuming your bin directory is in your path):
mv tale ~/bin
Once all this is in place your script will run from anywhere, whichever shell you are using.
There is an alternative approach called "alias" which could be use.
alias tale="./tale.sh"
or
alias tale="tail -f ~/lp/_logs/error.log"
This lasts until session is not terminated. It can be persists by making an entry in .bashrc or .bash_aliases file.
You can try with the below one line command :)
chmod +x tale.sh && bash tale.sh;

Preventing to start bash script with ./ (dot slash)

I wrote a lot of bash scripts that should work with the current bash session, because I often used fg, jobs, etc.
I always starts my scripts with . script.sh but one of my friends startet it with ./script.sh and got error that fg "couldn't be executed".
Is it possible to force a . script.sh or anything else what I can do to prevent errors? Such as cancel the whole script and print an error with echo or something else.
Edit:
I think bashtraps have problems when executing sourced, is there any way to use fg, jobs and bashtraps in one script?
Looks like you're trying to determine if a script is being run interactively or not. The bash manual says that you can determine this with the following test:
#! /bin/bash
case "$-" in
*i*) echo interactive ;;
*) echo non-interactive ;;
esac
sleep 2 &
fg
If you run this with ./foo.sh, you'll see "non-interactive" printed and an error for the fg built-in. If you source it with . foo.sh or source foo.sh you won't get that error (assuming you're running those from an interactive shell, obviously).
For your use-case, you can exit with an error message in the non-interactive mode.
If job control is all you need, you can make it work both ways with #!/bin/bash -i:
#!/bin/bash -i
sleep 1 &
fg
This script works the same whether you . myscript or ./myscript.
PS: You should really adopt your friend's way of executing scripts. It's more robust and most people write their scripts to work that way (e.g. assuming exit will just exit the script).
There are a couple of simple tricks to remind people to use source (or .) to run your script: First, remove execute permission from it (chmod -x script.sh), so running it with ./script.sh will give a permission error. Second, replace the normal shebang (first line) with something like this:
#!/bin/echo please run this with the command: source
This will make the script print something like "please run this with the command: source ./script.sh" (and not run the actual script) if someone does manage to execute it.
Note that neither of these helps if someone runs the script with bash script.sh.

Run script automatically on startup: script doesn't work correctly

I want to run a bash script on startup of my Parallella board, which has Ubuntu. I searched in SO, and found the instruction in here:
Run automatically program on startup under linux ubuntu
Programmatically run at startup on Linux?
My bash script is test.sh, which has only one line:
echo "Hello World" &> /home/qsp/WIP/test/hello.txt
1) The first way I tried is adding to /etc/rc.local the aboslute path to the script:
/home/qsp/WIP/test/test.sh
2) The second way I tried is following the accepted answer above.
sudo mv test.sh /etc/init.d/
sudo update-rc.d test.sh defaults
In both cases, the script was executed after booting, and there was a file hello.txt created in the folder. However, the content of the file is empty (and the owner is root). I wonder if I'm missing anything. Thank you.
======UPDATE=======
Following the answer of Skynet, I change my script to:
echo "Hello World" | tee /home/qsp/WIP/test/hello.txt
and the script writes to the file after booting correctly. I have another question, why my original script with &> didn't work, although it still works if running from command line.
You should make it in init script style, as cited by the first SO question. Like so:
case "$1" in
start)
#startup code
;;
stop)
#stop code
;;
restart)
#restart code
;;
esac
Also take a look at https://github.com/fhd/init-script-template/blob/master/template
After editing /etc/rc.local and adding your commands,
check your script must always end with exit 0.
Also make it sure you made it executable by using chmod command
chmod 777 test.sh
Change the line of output as
echo "Hello World" | tee /home/qsp/WIP/test/hello.txt
Create .desktop file and configure your ystem to auto-start at the time of login
Create .desktop file as below
$ vim ~/.config/autostart/test_script.desktop
add the below information
[Desktop Entry]
Type=Application
Name=Test script
Exec=~/test.sh
X-GNOME-Autostart-enabled=true
Note that ~/test.sh should point to the script you've created. Save it.
Make it executable:
$ chmod o+x ~/.config/autostart/test_script.desktop
Reboot and for the next login your script should run.

cp command won't run if executed from shell script

i have very simple shell script
#!/bin/bash
cp -rf /var/www/ksite/app2/* /var/www/ksite/app
echo "----"
echo "done"
but seems cp command fails
if i execute
cp -rf /var/www/ksite/app2/* /var/www/ksite/app
from terminal everything work ok. Can someone tell me how to include cp in shell script?
Thanks
We seem to have doubt as to how this script fails. If there is no error message then this is a strange one. I suggest:
On the command line (which works), do a which cp
Whatever the reply, then copy that and use it as the cp in the script (e.g. /bin/cp)
Check the widcard expansion, run your script with bash -x script-name and see if you get what you expect.
echo $? after the copy in the script - if it is zero then it (thinks it) worked.
Do a ls -ld /var/www/ksite/app from your script, maybe someone set a symbolic link?
If it still fails, source the script from the command-line and see if that works . script-name
Double check that the copy did actually fail! (maybe that should be step 1.)
Make sure you really have bash at /bin/bash. I think a batter hash bang is:
#!/usr/bin/env bash
This uses the env command to locate the bash binary and set the environment.
I had similar problem. What helped me:
I used windows and putty to write script, so I had \r\n at the end of lines. Be sure, you have only \n symbol.
I copied files and the only way it worked for me at script was cp <source_dir>/fileName <dest_dir>/fileName whereas at command line cp <source_dir>/fileName <dest_dir> worked well too.
Just covering all the bases .. do the permissions vary between the excutions .. i.e. do you execute one with sudo/root privileges, the other as user (unlikely, but thought I'd ask since we don't know what the exact error is)
Similar issue to Vladmir where the script was created in Windows. I created a new file "my_bash_script.sh" in the linux environment using VIM, then read the contents of my script into the file:
:r file_made_in_windows.sh
Then I saved, closed, then set the file as executable:
chmod 744 my_bash_script.sh
From there, I ran the script:
./my_bash_script.sh
...and it worked. What a weird issue. I was confounded for a moment.

Resources