Hi I'm pretty new to linux/bash in general and I'm having a some trouble making a script for my coworker. Idea of this script is to help automate coworkers IP table entries (don't use IP tables myself so no idea how it works, just working as per his instructions). Program is going to ask a few questions, form an entry and then add it to a file on a different host. After the file is written it will also run
"systemctl reload iptables.service" and "systemctl status iptables". I tested that pwd was atleast working where I was planning to put these.
The code worked fine with a single word in place of table_entry variable, I was able to write something to a file in my host computer with a different user.
Problem is that the "table_entry" variable is going to have whitespaces in it and the sudo su -c command gets the second word as input (atleast that's what I think is happening) and I get an error sudo: INPUT: command not found. the "INPUT" coming from my case sentence
I tried to put the "table_entry" variable in "{$table_entry}" , "$table_entry" and {$table_entry} forms but they didn't work.
I removed some of the code to make it more readable (mostly case sentences for variables and asking for host and username).
#!/bin/bash
echo -e "Which ports?
1. INPUT
2. OUTPUT
3. Forward"
read opt_ch
case $opt_ch in
1) chain="INPUT" ;;
2) chain="OUTPUT" ;;
3) chain="FORWARD" ;;
*) echo -e "Wrong Option Selected!!!"
esac
table_entry="-A $chain "#-s $ip_source -d $ip_dest
ssh -t user#host "sudo table_entry=$table_entry su -c 'echo $table_entry >> /home/user/y.txt'"
#^ this line will later also include the systemctl commands separated with ";" ^
I tested few different methods how to do this script overall, heredoc(didn't get input to work very well), Ansible(Didn't really seem like a great tool for this job), Python(can't install new modules to the enviroment). So this is the best solution I came up with bearing my limited skillset.
Edit: I also realise this is propably not the smartest way to do this script, but it's the only one I have gotten to work this far, that can also ask for a password from the user when doing su command. I'm not knowledgeable in transferring passwords safely in linux enviroment or in general, so I like to let linux handle the passwords for me.
This a problem with dealing with nested quoting - which is really quite the annoying problem to solve.
This case seems like you could do this with quotes inside the string - your example would become
ssh -t user#host "sudo table_entry='$table_entry' su -c 'echo \"$table_entry\" >> /home/user/y.txt'"
It seems to me the table_entry='$table_entry' is redundant though, this should work:
ssh -t user#host "sudo su -c 'echo \"$table_entry\" >> /home/user/y.txt'"
Your comment (denoted with #) is getting concatenated with the table_entry string you're trying to form. Try adding a space like this:
table_entry="-A $chain " #-s $ip_source -d $ip_dest
Then table_entry gets assigned correctly. I was using KWrite to edit your bash script, and it does text highlighting that quickly showed me the problem.
I'm running a Minecraft server, I want to make an sh script that when run, will attach to a screen and issue commands to the server. This is especially useful for long commands that may need multiple other commands to run.
I've tried screen -x zencraft/zencraft bash -c say test. But that didn't work. Neither did screen -x zencraft/zencraft bash -c echo -e "$(say test)" (but I didn't expect that to work anyway, because putting commands in $() in an echo just runs it as bash.)
I'm clueless on what to do at this point.
Note: The screen is shared between users and zencraft owns the screen. This is why using +x zencraft/zencraft is required.
I've figured this out myself, thanks to the help of some people.
screen -S zencraft/zencraft -p 0 -X stuff 'command' works. The stuff command is the key here - it actually does the magic of running the command, from what I know.
I am trying to schedule the execution of a shell-script with the Linux tool "at".
The shell script (video.sh) looks like this:
#!/bin/sh
/usr/bin/vlc /home/x/video.mkv
The "at" command:
at -f /home/x/video.sh -t 201411052225
When the time arrives, nothing happens.
I can execute the shell-script just fine via console or by rightclicking - Execute. VLC starts like it is supposed to. If I change the script to e.g. something simple like
#!/bin/sh
touch something.txt
it works just fine.
Any ideas, why "at" will not properly execute a script that starts a graphical program? How can I make it work?
You're trying to run an X command (a graphical program) at a scheduled time. This will be extremely difficult, and quite fragile, because the script won't have access to the X server.
At the very least, you will need to set DISPLAY to the right value, but even then, I suspect you will have issues with authorisation to use the X screen.
Try setting it to :0.0 and see if that works. But if you're logged out, or the screensaver's on, or any number of other things...
(Also, redirect vlc's stdout and stderr to a file so that you can see what went wrong.)
Your best bet might be to try something like xuserrun.
I suspect that atd is not running. You have to start the atd daemon before (and to set DISPLAY variable like chiastic-security said) ;)
You can test if atd is running with
pidof atd &>/dev/null && echo 'ATD started' || echo >&2 'ATD not started
Your vlc command should be :
DISPLAY=:0 /usr/bin/vlc /home/x/video.mkv
(Default display)
I have the following bash script to update to my website my current ip. It works fine stand alone, but put into a startup file, fails upon startup. I'm guessing it's a sequencing thing, but I'm not sure how to fix the sequencing, and after a few hours of googling and trying everything I can think of, I'm hoping someone can lead me in the right direction! This is what I am trying to run:
#!/bin/sh
IP_ADDR=$(ifconfig eth0 | sed -rn 's/^.*inet addr:(([0-9]+\.){3}[0-9]+).*$/\1/p')
wget -q -O /dev/null http://example.com/private/RPi_IP.php?send=${IP_ADDR}
I can't figure out what to do. I tried adding it to other startup programs even, and it fails upon startup too. I'm using a Raspberry Pi. Any ideas?
Your path might not be what you expect. You should fully-qualify any commands that you use. Especially for programs that live in /sbin/
ie
/sbin/ifconfig
/usr/bin/sed
/usr/bin/wget
I feel silly asking this...
I am not an expert on shell scripting, but I am finally in enough of a sysadmin role that I want to do this correctly.
I have a production server that hosts a webapp. Here is my routine.
1 - ssh to server
2 - cd django_src/django_apps/team_proj
3 - svn update
4 - sudo /etc/init.d/apache2 restart
5 - logout
I want to create a shell script for steps 2,3,4.
I can do this, but it will be a very plain and simple bash script simply containing the actual commands I type at the command line.
My question: What is the best way to script this kind of repetitive procedure in bash (Linux, Ubuntu) for a remote server?
Thanks!
The best way is simply as you suggest. Some things you should do for your script would be:
put set -e at the top of the script (after the shebang). This will cause your script to stop if any of the commands fail. So if it cannot cd to the directory, it will not run svn update or restart apache. You can do this programmatically by putting || exit 0 after each command, but if that's all you're doing, you may as well use set -e
Use full paths in your script. Do not assume the directory that the script is run from. In this specific case, the cd command has a relative path. Use a full (absolute) path, or use an environment variable like $HOME.
You may want to set up sudo so that it can run the command without asking for a password. This makes your script non-interactive which means it can be run in the background and from cron jobs and such.
As time goes by, you may add features and take command line arguments to parameterise the script. But don't bother doing this up front. Just evolve your scripts as you need.
There is nothing wrong with a simple bash script simply containing the actual commands you type at the command line. Don't make it more complicated than necessary.
I'd setup a cron job doing that automatically.
Since you're using python, check out fabric - you can use it to automate these kind of tasks. First install fabric:
$ sudo easy_install fabric
then write your fabric script:
from __future__ import with_statement
from fabric.api import *
def svnupdate():
with cd('django_src/django_apps/team_proj'):
run('svn update')
sudo('/etc/init.d/apache2 restart')
Save as fabfile.py, then run using the fab command:
$ fab -H hostname svnupdate
Tell me that's not cool! :-)
you can do this with the shell (bash,ksh,zsh + ssh + tools), or programming languages such as Python,Perl(Ruby or PHP or Java) etc, basically a language that supports SSH protocol and operating system functions. The "best" one is the one that you are more comfortable and have knowledge in. If you are doing sysadmin, the shell is the closest thing you can use. Then after you have done your script, you can use the crontab (cron) , or the at command to schedule your task. check their man page for more information
You can easily do the above using bash/Bourne etc.
However I would take the time and effort to learn Perl (or some similarly powerful scripting language). Why ?
the language constructs are much more powerful
there are no end of libraries to interface to the systems/features you want to script
because of the library support, you won't have to spawn off different commands to achieve what you want (possibly valuable on a loaded system)
you can decompose frequently-used scripts into your own libraries for later use
I choose Perl particularly because it's been designed (perhaps designed is too strong a word for Perl) for these sort of tasks. However you may want to check out Ruby/Python or other suggestions from SO contributers.
For the basic steps look at camh's answer. If you plan to run the script via cron, then implement some simple logging, e.g. by appending start time of each command with exit code to a textfile which you can later analyze for failures of the script.
Expect -- scripting interactive applications
Expect is a tool for automating interactive applications such as telnet, ftp, passwd, fsck, rlogin, tip, etc.... Expect can make easy all sorts of tasks that are prohibitively difficult with anything else. You will find that Expect is an absolutely invaluable tool - using it, you will be able to automate tasks that you've never even thought of before - and you'll be able to do this automation quickly and easily.
http://expect.nist.gov
bonus: Your tax dollars at work!
I would probably do something like this...
project_update.sh
#!/bin/bash
#
# $1 - user#host
# $2 - project directory
[[ -z $1 || -z $2 ]] && { echo "usage: $(basename $0) user#host project_dir"; exit 1; }
declare host=$1 proj_dir=$2
ssh $host "cd $proj_dir;svn update;sudo /etc/init.d/apache2 restart" && echo "Success"
Just to add another tip - you should not give users access to some application in an unknown state. svn up might break during the update, users might see a page that's half-new half-old, etc. If you're deploying the whole application at once, I'd suggest doing svn export instead to a new directory and then either mv current old ; mv new current, or even keeping current as a link to the directory you're using now. Still not perfect and not blocking every possible race condition, but it definitely takes less time than svn up on the live copy.