I have installed a backup program called rclone on my raspberry pi which is running Debian, I have successfully ran the cmd in the shell to backup a folder to google drive but I really need to be able to do so each time a take a photo with my python script, I have little experience in Linux compared to others and I thought that if I made a shell script with a basic shebang of
#!/bin/sh
or
#!/bin/bash
then the cmd below
rclone copy /var/www/html/camera_images pictures::folder1
I then made the .sh file executable, and this works if I just click it in the folder and execute but if I try to call that .sh script from python with
os.system('sh /home/pi/py/upload.sh')
or
os.system(' rclone copy /var/www/html/camera_images pictures::folder1 ')
I get an error in the shell saying
Failed to load config file "/root/.rclone.conf" using default - no such directory.
But the .conf is located in /home/pi as it should be. and if i try
os.system(' sh rclone copy /var/www/html/camera_images pictures::folder1 ')
I get
sh: 0: Cant open rclone.
How can I can run the copy cmd or a script to do so from python?
this is how i installed rclone
cd
wget http://downloads.rclone.org/rclone-v1.34-linux-arm.zip
unzip rclone-v1.34-linux-arm.zip
cd rclone-v1.34-linux-arm
sudo cp rclone /usr/sbin/
sudo chown root:root /usr/sbin/rclone
sudo chmod 755 /usr/sbin/rclone
sudo mkdir -p /usr/local/share/man/man1
sudo cp rclone.1 /usr/local/share/man/man1/
sudo mandb
rclone config
Use --config in your rclone command
From docs:
--config string Config file. (default /home/ncw/.rclone.conf")
Your command should looks like:
os.system(' sh rclone copy --config /home/pi/.rclone.conf /var/www/html/camera_images pictures::folder1 ')
You should be using subprocess module instead of os.system.
You can use subprocess.Popen to create a process and give it a working directory.
subprocess.Popen(your_command, cwd=path_to_your_executable_dir, shell=True)
(Use shell=True to pass a simple string command among other conveniences).
The shell argument (which defaults to False) specifies whether to use
the shell as the program to execute. If shell is True, it is
recommended to pass args as a string rather than as a sequence.
On Unix with shell=True, the shell defaults to /bin/sh. If args is a
string, the string specifies the command to execute through the shell.
This means that the string must be formatted exactly as it would be
when typed at the shell prompt. This includes, for example, quoting or
backslash escaping filenames with spaces in them. If args is a
sequence, the first item specifies the command string, and any
additional items will be treated as additional arguments to the shell
itself. That is to say, Popen does the equivalent of: ....
Thank you every one :)
I have it working now with
os.system(' rclone copy --config /home/pi/.rclone.conf /var/www/html/camera_images pictures::folder1 ')
Note that if i put sh at the start i got the error sh: 0: Can't open rclone though i read yesterday about putting something like ,:0 at the end as a return value ? either way it works without the sh.
and the subprocess works too which i shall use instead.
subprocess.Popen('rclone copy --config /home/pi/.rclone.conf /var/www/html/camera_images pictures::folder1', shell=True)
Related
I have a shell script which I want to run without using the "sh" or "bash" commands. For example:
Instead of: sh script.sh
I want to use: script.sh
How can I do this?
P.S. (i) I don't use shell script much and I tried reading about aliases, but I did not understand how to use them.
(ii) I also read about linking the script with another file in the PATH variables. I am using my university server and I don't have permissions to create a file in those locations.
Add a "shebang" at the top of your file:
#!/bin/bash
And make your file executable (chmod +x script.sh).
Finally, modify your path to add the directory where your script is located:
export PATH=$PATH:/appropriate/directory
(typically, you want $HOME/bin for storing your own scripts)
These are the prerequisites of directly using the script name:
Add the shebang line (#!/bin/bash) at the very top.
Use chmod u+x scriptname to make the script executable (where scriptname is the name of your script).
Place the script under /usr/local/bin folder.
Note: I suggest placing it under /usr/local/bin because most likely that path will be already added to your PATH variable.
Run the script using just its name, scriptname.
If you don't have access to /usr/local/bin then do the following:
Create a folder in your home directory and call it bin.
Do ls -lA on your home directory, to identify the start-up script your shell is using. It should be either .profile or .bashrc.
Once you have identified the start up script, add the following line:
PATH="$PATH:$HOME/bin"
Once added, source your start-up script or log out and log back in.
To source, put . followed by a space and then your start-up script name, e.g. . .profile or . .bashrc
Run the script using just its name, scriptname.
Just make sure it is executable, using chmod +x. By default, the current directory is not on your PATH, so you will need to execute it as ./script.sh - or otherwise reference it by a qualified path. Alternatively, if you truly need just script.sh, you would need to add it to your PATH. (You may not have access to modify the system path, but you can almost certainly modify the PATH of your own current environment.) This also assumes that your script starts with something like #!/bin/sh.
You could also still use an alias, which is not really related to shell scripting but just the shell, and is simple as:
alias script.sh='sh script.sh'
Which would allow you to use just simply script.sh (literally - this won't work for any other *.sh file) instead of sh script.sh.
In this example the file will be called myShell
First of all we will need to make this file we can just start off by typing the following:
sudo nano myShell
Notice we didn't put the .sh extension?
That's because when we run it from the terminal we will only need to type myShell in order to run our command!
Now, in nano the top line MUST be #!/bin/bash then you may leave a new line before continuing.
For demonstration I will add a basic Hello World! response
So, I type the following:
echo Hello World!
After that my example should look like this:
#!/bin/bash
echo Hello World!
Now save the file and then run this command:
chmod +x myShell
Now we have made the file executable we can move it to /usr/bin/ by using the following command:
sudo cp myShell /usr/bin/
Congrats! Our command is now done! In the terminal we can type myShell and it should say Hello World!
You have to enable the executable bit for the program.
chmod +x script.sh
Then you can use ./script.sh
You can add the folder to the PATH in your .bashrc file (located in your home directory).
Add this line to the end of the file:
export PATH=$PATH:/your/folder/here
You can type sudo install (name of script) /usr/local/bin/(what you want to type to execute said script)
ex: sudo install quickcommit.sh /usr/local/bin/quickcommit
enter password
now can run without .sh and in any directory
Add . (current directory) to your PATH variable.
You can do this by editing your .profile file.
put following line in your .profile file
PATH=$PATH:.
Just make sure to add Shebang (#!/bin/bash) line at the starting of your script and make the script executable(using chmod +x <File Name>).
Here is my backup script that will give you the idea and the automation:
Server: Ubuntu 16.04
PHP: 7.0
Apache2, Mysql etc...
# Make Shell Backup Script - Bash Backup Script
nano /home/user/bash/backupscript.sh
#!/bin/bash
# Backup All Start
mkdir /home/user/backup/$(date +"%Y-%m-%d")
sudo zip -ry /home/user/backup/$(date +"%Y-%m-%d")/etc_rest.zip /etc -x "*apache2*" -x "*php*" -x "*mysql*"
sudo zip -ry /home/user/backup/$(date +"%Y-%m-%d")/etc_apache2.zip /etc/apache2
sudo zip -ry /home/user/backup/$(date +"%Y-%m-%d")/etc_php.zip /etc/php
sudo zip -ry /home/user/backup/$(date +"%Y-%m-%d")/etc_mysql.zip /etc/mysql
sudo zip -ry /home/user/backup/$(date +"%Y-%m-%d")/var_www_rest.zip /var/www -x "*html*"
sudo zip -ry /home/user/backup/$(date +"%Y-%m-%d")/var_www_html.zip /var/www/html
sudo zip -ry /home/user/backup/$(date +"%Y-%m-%d")/home_user.zip /home/user -x "*backup*"
# Backup All End
echo "Backup Completed Successfully!"
echo "Location: /home/user/backup/$(date +"%Y-%m-%d")"
chmod +x /home/user/bash/backupscript.sh
sudo ln -s /home/user/bash/backupscript.sh /usr/bin/backupscript
change /home/user to your user directory and type: backupscript anywhere on terminal to run the script! (assuming that /usr/bin is in your path)
Enter "#!/bin/sh" before script.
Then save it as script.sh for example.
copy it to $HOME/bin or $HOME/usr/bin
The directory can be different on different linux distros but they end with 'bin' and are in home directory
cd $HOME/bin or $HOME/usr/bin
Type chmod 700 script.sh
And you can run it just by typing run.sh on terminal.
If it not work, try chmod +x run.sh instead of chmod 700 run.sh
Make any file as executable
Let's say you have an executable file called migrate_linux_amd64 and you want to run this file as a command like "migrate"
First test the executable file from the file location:
[oracle#localhost]$ ./migrate.linux-amd64
Usage: migrate OPTIONS COMMAND [arg...]
migrate [ -version | -help ]
Options:
-source Location of the migrations (driver://url)
-path Shorthand for -source=file://path
-database Run migrations against this database (driver://url)
-prefetch N Number of migrations to load in advance before executing (default 10)
-lock-timeout N Allow N seconds to acquire database lock (default 15)
-verbose Print verbose logging
-version Print version
-help Print usage
Commands:
goto V Migrate to version V
up [N] Apply all or N up migrations
down [N] Apply all or N down migrations
drop Drop everyting inside database
force V Set version V but don't run migration (ignores dirty state)
version Print current migration version
Make sure you have execute privileges on the file
-rwxr-xr-x 1 oracle oinstall 7473971 May 18 2017 migrate.linux-amd64
if not, run chmod +x migrate.linux-amd64
Then copy your file to /usr/local/bin. This directory is owned by root, use sudo or switch to root and perform the following operation
sudo cp migrate.linux-amd64 /usr/local/bin
sudo chown oracle:oracle /user/local/bin/migrate.linux.amd64
Then create a symbolic link like below
sudo ln /usr/local/bin/migrate.linux.amd64 /usr/local/bin/migrate
sudo chown oracle:oracle /usr/local/bin/migrate
Finally add /usr/local/bin to your path or user profile
export PATH = $PATH:/usr/local/bin
Then run the command as "migrate"
[oracle#localhost]$ migrate
Usage: migrate OPTIONS COMMAND [arg...]
migrate [ -version | -help ]
Options:
-source Location of the migrations (driver://url)
-path Shorthand for -source=file://path
-database Run migrations against this database (driver://url)
-prefetch N Number of migrations to load in advance before executing (default 10)
-lock-timeout N Allow N seconds to acquire database lock (default 15)
-verbose Print verbose logging
-version Print version
-help Print usage
Commands:
goto V Migrate to version V
up [N] Apply all or N up migrations
down [N] Apply all or N down migrations
drop Drop everyting inside database
force V Set version V but don't run migration (ignores dirty state)
version Print current migration version
Make the script file as executable by using file's properties
Create alias for the executable in ~/.bashrc. alias <alias namme> = <full script file path>'
refresh the user session to apply it. source ~/.bashrc
Just to add to what everyone suggested. Even with those solutions, the problem will persist if the user wants to execute the script as sudo
example:
chmod a+x /tmp/myscript.sh
sudo ln -s /tmp/myscript.sh /usr/local/bin/myscript
typing myscript would work but typing sudo myscript would return command not found.
As sudo you would have to still type sudo sh myscript or sudo bash myscript.
I can't think of a solution around this.
Just:
/path/to/file/my_script.sh
I'm attempting to create a .sh file to batch a number of runs of a neural network on Python whilst on holidays.
At the moment I have been calling this from the command line:
python neural_network_trainer.py [args]
I now have a .sh script written:
#!/bin/bash
python neural_network_trainer.py [args]
# Repeated with varied args
That I am attempting to call in the same terminal as the original command line was running:
./august_hols.sh
I get the following error:
File "/data/Python-3.6.9/lib/python3.6/site.py", line 177
file=sys.stderr)
^
SyntaxError: invalid syntax
Where the Python install is in /data (for reasons).
Running which on the command line reports the correct Python directory set via an alias in ~/.bashrc:
alias python=/data/Python-3.6.9/bin/python3
But running which between the Bash shebang and the first python call reports /bin/python.
I've attempted to set the alias again at the start of the .sh script to no avail. I'm scratching my head as this is exact process I have used elsewhere, albeit not on this precise PC. I can copy the exact command from the top of the bash file into the terminal and it runs fine, try and call ./august_hols.sh and get the above Python error.
Where is Bash getting that path from, and why is it not using my expected route through ~/.bashrc?
Bash sub-shell does not inherit alias in the main shell
You can source the script (run in the main shell), instead of execute it (run in the sub-shell)
source script.sh
EDIT:
Solution 2:
Run bash as the login shell so ~/.bashrc is executed, so your alias is loaded before your script.
The subshell needs to be interactive to enable alias, because alias is enabled by default only for interactive shell, but script is non-interactive by default.
bash --login -i script.sh
Solution 3:
Similar to above, except alias is enabled explicitly
bash --login -O expand_aliases script.sh
Have you tried:
python=/data/Python-3.6.9/bin/python3 ./[your_bash].sh
In your .sh
Do this
#!/usr/bin/env bash
export PATH=/data/Python-3.6.9/bin:$PATH
exec python neural_network_trainer.py "$#"
Aliases are tricky.
A maybe more nasty solution
mapfile < <(declare -p | grep -m 1 BASH_ALIASES) && bash script.sh "${MAPFILE[#]}"
within your script you will need
shopt -s expand_aliases
eval $1
echo ${BASH_ALIASES[python]}
python --version
How about this:
#!/bin/bash
/data/Python-3.6.9/bin/python3 neural_network_trainer.py [args]
# Repeated with varied args
I have a simple python script which I want to start a daemon-service in background in docker container
/sbin/start-stop-daemon --start --user root --make-pidfile --pidfile /var/lock/subsys/my-application.pid --exec 'python /opt/app/uc/monitor/bin/my-application.py'
when I execute this command in a shell I get
/sbin/start-stop-daemon: unable to stat //python /opt/app/uc/monitor/bin/my-application.py (No such file or directory)
However when execute just the below command in shell it works
python /opt/app/uc/monitor/bin/my-application.py
I'm sure the python is installed and all the links have been setup.
Thanks for the help
That error message implies that start-stop-daemon is looking for a file to open (the stat operation is a check before it opens the file) and treating your 'python ... ' argument as if it was a file.
See this example which confirms this. You may need to read the man page for start-stop-daemon, for your Ubuntu version, to check what a valid command would be for your setup.
Simplest solution is probably to create a shell script (say /opt/app/uc/monitor/bin/run-my-application.sh), and put this into it:
#!/bin/bash
python /opt/app/uc/monitor/bin/my-application.py
Be sure to do chmod +x on this file. If python is not found, use which python to find the path to python and use that in the script.
Now try:
/sbin/start-stop-daemon --start --user root --make-pidfile --pidfile /var/lock/subsys/my-application.pid --exec '/opt/app/uc/monitor/bin/run-my-application.sh'
I'm trying to run a shell command with docker-py on an already-running container, but get an error:
exec: "export": executable file not found in $PATH
here's how I wrote the script:
exe = client.exec_create(container=my_container, cmd='export MYENV=1')
res = client.exec_start(exec_id=exe)
so my question is how can I run a shell command (inside the container) using docker-py?
You did it quite right. But you confused shell commands with linux executables. exec_create and and exec_start are all about running executables. Like for example bash. export in your example is a shell command. You can only use it in a shell like bash running inside the container.
Additionally what you are trying to achieve (setting a environment variable) is not going to work. As soon as your exec finishes (where you set the env var) the exec process will finish and its environment is been torn down.
You can only create global container environment variables upon creation of a container. If you want to change the env vars, you have to tear down the container and recreate it with your new vars. As you probably know, all data in the container is lost upon a remove unless you use volumes to store your data. Reconnect the volumes on container creation.
That said your example was nearly correct. This should work and create an empty /somefile.
exe = client.exec_create(container=my_container, cmd=['touch', '/somefile'])
res = client.exec_start(exec_id=exe)
To execute shell commands, use this example. It calls sh and tells it to run the interpreter on the given command string (-c)
exe = client.exec_create(container=my_container,
cmd=['/bin/sh', '-c', 'touch /somefile && mv /somefile /bla'])
res = client.exec_start(exec_id=exe)
For actually , when execute cmd docker exec in docker container export MYENV=1. It will fail and report this error
exec: "export": executable file not found in $PATH
Because export is a shell builtin, could run the cmd in shell.
whereis export
type export
can not find export in /usr/bin/ or somewhere else.
There is some ways to pass through this problem.
case1: use -c parameter
/bin/bash -c 'export MYENV=1 ; /bin/bash'
case2: append export cmds to a rcfile, then use this file.
echo "exprot MYENV=1" >> <some_file_path> ; /bin/bash --rcfile <some_file_path>
case3: open a terminal, then enter the cmds to export env parameters , then open a new terminal, the env parameters will work.
/bin/bash
exprot MYENV=1
/bin/bash # open a new terminal
I want to run IDLE3.2 with the argument "-s" so it can read ".pythonstartup" and export relevant modules, change the working directory and etc. Here is what I have tried:
Created a shell script:
/usr/local/bin/idle3.2 -s
this works allright, however running the script from the Finder opens up the Terminal, which is not the desired behavior.
Created an applescript:
do shell script "/bin/bash; cd /usr/local/bin/; ./idle3.2 -s"
this get rids of the terminal however fails to pass "-s" argument to idle3.2 so the configuration file is not loaded.
any suggestions?
EDIT: turns out environment variables are not properly set even though /bin/bash is called. so the following solves the problem:
do shell script "/bin/bash; source ~/.profile; /usr/local/bin/idle3.2 -s"
I think your do shell script "/bin/bash; cd /usr/local/bin; ./idle3.2 -s" is doing extra work, and can probably be done more simply. Try:
do shell script "/usr/local/bin/idle3.2 -s"
thanks to #lain the following applescript solves the problem:
do shell script "source ~/.profile; idle3.2 -s"
where ~/.profile points the shell (in this case /bin/sh) the path for .PYTHONSTARTUP and the path for idle3.2