variable in scp filename not working? - bash

I'm trying to scp a backup tgz file from one server to another every night. The backup script uses the following $date var just fine but when I modify it slightly for scp it breaks:
#!/bin/sh
date=`date +%Y-%m-%d`
rbfile=`/backups/$date_00h00.tgz`
scp $rbfile user#myserverip:
But the script dies with the error:
/backups/.tgz: No such file or directory
On a side note, I really should switch to rsync for better remote backups - the tgz files are at 3.5GB now. Any recommended tutorials?

when using $date_00h00 you tell bash to use the variable named date_00h00, because letters, numbers and _ characters are allowed as variables names.
Enclose the variable name in {} and it will correct the problem :
rbfile=`/backups/${date}_00h00.tgz`

Related

Bash Shell Script Issues

I am new to UNIX and have a homework assignment that is giving me trouble. I am to write a script that will back up specified files from the current directory into a specified destination directory. This script is to take three arguments.
sourcePath, which is the path to the source files/files being backed up or copied.
backupPath, which is the path to the target directory where the files will be backed up.
filePrefix, which is used to identify which files to backup, specifically only files whose names begin with the given prefix will be copied while others will be ignored. Example would be, if the user enters the letter "d", then all files starting with that letter are to be copied while any other file is to be ignored.
I haven't learned much about scripting/functions in bash so I've tried looking up tutorials which have been helpful but not enough. This script is something I can easily do when just typing out the commands. For instance, I would cd into the target directory that has the files, then using the cp command copy files that begin with the specific prefix to the target directory, but when making a script I am at a dead end.
I feel as though my code is monumentally incorrect and its due to my lack of experience, but nothing online has been of any help. So far my code is
read sourcePath
read backupPath
read filePrefix
grep /export/home/public/"$sourcePath
mkdir -p $backupPath
cp /export/home/public/"$sourcePath"/$filePrefix /home/public/"$backupPath"
So an example execution of the script would be
$ ./script.sh
(sourcePath)HW4testdir (backupPath)backup (filePrefix)d
Output:
backing up: def (example file starting with d)
backing up: dog (example file starting with d)
So far when executing the code, nothing happens. Again, I'm sure most, or even all of the code is wrong and totally off base, but I never learned about scripting. If I did not have to create a script, I could easily achieve this desired outcome.
I suggest with bash:
read -r -p "sourcePath: " sourcePath
read -r -p "backupPath: " backupPath
read -r -p "filePrefix: " filePrefix
mkdir -p /home/public/"$backupPath"
cp /export/home/public/"$sourcePath/$filePrefix"* /home/public/"$backupPath"
Make sure that the used user has the right to create the directory /home/public/"$backupPath".
See: help read
For a start: Your assignment states, that your script should accept arguments.
However your script does not take arguments. It reads the parameters from standard input. Arguments are passed to the script on the command line, and your script would be called as
./script.sh HW4testdir backup d
Hence you can't use read to fetch them. The first argument is available under the name $1, the second argument is $2 and so on. You could write for instance
sourcePath=${1?Parameter missing}
which has the side effect to abort the script with an error message, if the caller forgets to pass the parameter.
Another point: You don't say anywhere that bash should be used to run the script. Since you want the script to be called by
./script.sh ....
and not by
bash ./script.sh ....
you must encode the information, that bash should be used, in your script. Assuming that your bash is located in /usr/bin, you would do this by making the first line of the script
#!/usr/bin/bash

Escaping parameter to bash function [duplicate]

This question already has answers here:
What does $# mean in a shell script?
(8 answers)
Closed 6 years ago.
First I'll describe the problem. I often copy files from my linux desktop to my android tablet. For reasons I'd rather not go into, the easiest way I found to do this is by running sshDroid (a ssh server) on my tablet, and using scp from the shell to copy files over. The scp command takes the following form:
scp -P 2222 ./some\ document\:\ with\ subtitle\ -\ author.txt \
root#197.157.0.211:/sdcard/uploads
The only thing that changes in this expression is the name of the file, and that is quite easily attained via tab-completion. Not even the ip address changes. Since I upload files quite often, I would very much like to not type the same characters over and over again. To this end I thought I would write a shell function and append it to .bashrc. The function I wrote is as follows:
upload(){ scp -P 2222 $# root#192.168.0.151:/sdcard/uploads; }
it's usage is supposed to be:
upload ./some\ document\:\ with\ subtitle\ -\ author.txt
but when I try it I get the following output:
SSHDroid
Use 'root' as username
Default password is 'admin'
root#192.168.0.151's password:
./some: No such file or directory
ssh: Could not resolve hostname document: Name or service not known
with: No such file or directory
subtitle: No such file or directory
-: No such file or directory
author.txt: No such file or directory
It looks like bash is automatically unescaping the filename before it passes it to the function, and the scp command treats it as multiple filenames due to the spaces in the name.
My question is: How do I preserve the backslashes in the parameter, or failing that how do I reescape it within the function? After fiddling with this for a while I'm sorely tempted to write a simple python script and drop it into /usr/local/bin. Is there some other bash-native solution that I'm missing?
Quotes!
Unquoted, $# behaves identically to $*; if you want to preserve original tokenization, you need to use "$#" instead. Thus:
upload() { scp -P 2222 "$#" root#192.168.0.151:/sdcard/uploads; }

scp multiple files in a shell script

I have a list of directory names.
I want to scp into a remote machine, go into each of my directory names and copy a file back to my local computer.
I so far have:
while read line
do
scp remote_machine:/home/$line/$line.dat ./local
done < file_with_directory_names.txt
I have authorisation keys set up so that I don't have to enter the password each time - but this method does login to the remote machine for every file it transfers. I imagine that there is a much better way than this.
You can specify multiple files in a single scp argument by separating them with spaces; you just need to make sure it's one argument to scp itself. This should work in your case:
scp "remote_machine:$(
sed 's,.*,/home/&/&.dat,' file_with_directory_names.txt | xargs)" ./local
The sed command sticks the /home/ prefix and name.dat suffix on each line; the xargs outputs all the resulting pathnames on a single line separated by spaces. Plug that all into the source argument after the remote_machine: part, all inside double quotes so it's still a single argument to scp, and you're good to go.

Shell Script Not Finding File

Hello I am trying to write a simple shell script to use in a cronjob to copy a backup archive of website files to a remote server via FTP.
The script below works when I type the file name in by hand manually, but with the date and filename specified as a variable it returns that it can't find ".tar.gz" as if it is ignoring the first part of the filename.
I would be grateful if someone could tell me where I am going wrong.
#!/bin/sh
NOW=$(date +"%F")
FILE="$NOW_website_files.tar.gz"
# set the local backup dir
cd "/home/localserver/backup_files/"
# login to remote server
ftp -n "**HOST HIDDEN**" <<END
user "**USER HIDDEN**" "**PASSWORD HIDDEN**"
cd "/backup_files"
put $FILE
quit
END
This is because it is looking for a variable name NOW_website_files which does not exist, and thus the resulting file name evaluates to .tar.gz.
To solve it, do:
#!/bin/sh
NOW=$(date +"%F")
FILE="${NOW}_website_files.tar.gz"
^ ^
instead of
FILE="$NOW_website_files.tar.gz"
This way it will concatenate the variable $NEW to the _website_files.tar.gz text.
You could do this:
FILE=$(date +"%F_website_files.tar.gz")
instead of this:
NOW=$(date +"%F")
FILE="$NOW_website_files.tar.gz"
IMPORTANT
By the way, consider adding "bi" to your FTP script as you are clealy PUTting a binary file and you don't want CR/LF translation to occur in binary files...

Rsync copies too many directories being executed via bash script

Originally I would like to sync directory (with all files and subdirectories) given in parameter in bash script.
I found this post: How can I recursively copy a directory into another and replace only the files that have not changed? which explains how to use rsync in similar case.
My bash script is quite simple and listed below:
#!/bin/bash
echo -e "Type the project to be deployed: \c "
read project
echo -e "* Deploying: $project *"
echo -e "Sync: /var/repo/released/$project"
echo -e " /var/www/released/$project"
rsync -pr /var/repo/released/$project /var/www/released/$project
As a result it copies everything within /released (there are many directories in there, let's say -projects-).
I would like to copy (sync) only project given in parameter.
Could you please advice how to do this?
When you call the script without an argument (which most likely is what you're doing since you interactively read the project name into the variable $project), the positional parameter $1 remains empty. Therefore the script will rsync the entire content of /var/repo/released/.
You need to replace $1 with $project in your script. Also, I'd recommend to put double quotes around the paths to avoid problems due to spaces in a directory name.
rsync -pr "/var/repo/released/$project" "/var/www/released/$project"

Resources