Bash pass date variable as string - bash

I have a script which creates another script when run like this:
cat > "$installpath""tweets.sh" << ENDOFFILE
#!/bin/bash
source "$installpath"config.sh
cd \$webdir
/usr/local/bin/twint -s "\$search" --limit \$scrapelimit -o \$csvname --csv --database \$dbfile -ho
FILE=\$csvname
NAME=\${FILE%.*}
EXT=\${FILE#*.}
DATE=`\date +%d-%m-%Y-%H-%M`
NEWFILE=\${NAME}_\${DATE}.\${EXT}
echo \$NEWFILE
mv \$csvname \$NEWFILE
export NEWFILE
export DATE
ENDOFFILE
However, the script interprets the
DATE=`\date +%d-%m-%Y-%H-%M`
and changes it to
DATE=28-09-2019-15-49
I have tried escaping the variables in every possible way but nothing seems to work. Any ideas?

I suggest to use:
DATE=\$(date +%d-%m-%Y-%H-%M)

Related

shell script variable being truncated - why

I have been trying to customise this very useful (in principle) backup to s3 script.
I really am not a shell scripter to any real level and I can't work out why this line
is truncating the variable.
so e.g.
DB=abcdefg
abcdefg_USER=testuser
USER=$(eval echo \$${DB}_USER)
The eval statement is returning bcdefg_USER so is truncating the variable and echoing out bcdefg_USER not abcdefg_USER and so isn't evaluating the variable abcdefg_USER
Running on an amazon linux ec2 instance.
Anyone explain to me what I am missing, I've tried playing around with the escaping and braces etc and echoing out each stage in the process but can't get a handle on what is going on.
Thanks
full script below:
## Specify data base schemas to backup and credentials
DATABASES="wp myotherdb"
## Syntax databasename as per above _USER and _PW
wp_USER=username
wp_PW=password
myotherdb_USER=username
myotherdb_PW=password
## Specify directories to backup (it's clever to use relaive paths)
DIRECTORIES="/var/www root etc/cron.daily etc/cron.monthly etc/apache2 etc/mysql etc/php5"
## Initialize some variables
DATE=$(date +%d)
BACKUP_DIRECTORY=/tmp/backups
S3_CMD="s3cmd"
## Specify where the backups should be placed
S3_BUCKET_URL=s3://mybackupbucket/$DATE/
## The script
cd /
mkdir -p $BACKUP_DIRECTORY
rm -rf $BACKUP_DIRECTORY/*
## Backup MySQL:s
for DB in $DATABASES
do
BACKUP_FILE=$BACKUP_DIRECTORY/${DB}.sql
USER=$(eval echo \$${DB}_USER)
PASSWORD=$(eval echo \$${DB}_PW)
/usr/bin/mysqldump -v -u $USER --password=$PASSWORD -h localhost -r $BACKUP_FILE $DB 2>&1
gzip $BACKUP_FILE 2>&1
$S3_CMD put ${BACKUP_FILE}.gz $S3_BUCKET_URL 2>&1
done
## Backup of config directories
for DIR in $DIRECTORIES
do
BACKUP_FILE=$BACKUP_DIRECTORY/$(echo $DIR | sed 's/\//-/g').tgz
tar zcvf ${BACKUP_FILE} $DIR 2>&1
$S3_CMD put ${BACKUP_FILE} $S3_BUCKET_URL 2>&1
done
Assuming that you are using bash, this is how to avoid eval:
$ DB=abcdefg
$ abcdefg_USER=testuser
$ tmpvar=${DB}_USER
$ USER=${!tmpvar}
$ echo $USER
testuser
If you have bash version 4, consider using associative arrays:
$ declare -A users
$ users[abcdefg]=testuser
$ echo "${users[$DB]}"
testuser
You're running into some weird bug involving command substitution and echo.
When using eval to access a computed variable name, it is not necessary to complicate things by involving echo wrapped in a process substitution. Try this pattern, which should work pretty much in any POSIX-like shell.
eval FINAL_VALUE=\$${COMPUTED_VAR_PREFIX}_FIXED_SUFFIX
That is to say, just generate the source code of the desired variable assignment, and eval that code.

Bash command as variable

I am trying to store the start of a sed command inside a variable like this:
sedcmd="sed -i '' "
Later I then execute a command like so:
$sedcmd s/$orig_pkg/$package_name/g $f
And it doesn't work. Running the script with bash -x, I can see that it is being expanded like:
sed -i ''\'''\'''
What is the correct way to express this?
Define a shell function:
mysed () {
sed -i "" "$#"
}
and call it like this:
$ mysed s/$orig_pkg/$package_name/g $f
It works when the command is only one word long:
$ LS=ls
$ $LS
But in your case, the shell is trying the execute the program sed -i '', which does not exist.
The workaround is to use $SHELL -c:
$ $SHELL -c "$LS"
total 0
(Instead of $SHELL, you could also say bash, but that's not entirely reliable when there are multiple Bash installations, the shell isn't actually Bash, etc.)
However, in most cases, I'd actually use a shell function:
sedcmd () {
sed -i '' "$#"
}
Why not use an alias or a function? You can do alias as
alias sedcmd="sed -i '' "
Not exactly sure what you're trying to do, but my suggestion is:
sedcmd="sed -i "
$sedcmd s/$orig_pkg/$package_name/g $f
You must set variables orig_pkg package_name and f in your shell first.
If you're replacing variable names in a file, try:
$sedcmd s/\$orig_pkg/\$package_name/g $f
Still f must be set to the file name you're working on.
This is the right way for do that
alias sedcmd="sed -i ''"
Obviously remember that when you close your bash, this alias will be gone.
If you want to make it "permanent", you have to add it to your .bashrc home file (if you want to make this only for a single user) or .bashrc global file, if you want to make it available for all users

Inserting variables into URLs with bash scripting

Say I want to write a bash script that takes user input, inserts it into a URL and then downloads it. Something like this:
#!/bin/bash
cd /path/to/folder
echo Which version?
read version
curl -O http://assets.company.tld/$version/foo.bar
Would this work? If not, how can I do what I'm trying to do?
#!/bin/bash
version=$1
cd /path/to/folder
echo $version
curl -o $version-foo.bar http://assets.company.tld/$version/foo.bar
where $1 is the first positional argument
So, suppose you save the script with name assets.sh. Then you can using the same like following:
./assests.sh ver1
where ver1 is the version
[EDIT] If you want an interactive session:
#!/bin/bash
version=$1
cd /path/to/folder
echo -n "Which version you want? "
read version
curl -o $version-foo.bar http://assets.company.tld/$version/foo.bar

OSX bash script works but fails in crontab on SFTP

this topic has been discussed at length, however, I have a variant on the theme that I just cannot crack. Two days into this now and decided to ping the community. THx in advance for reading..
Exec. summary is I have a script in OS X that runs fine and executes without issue or error when done manually. When I put the script in the crontab to run daily it still runs but it doesnt run all of the commands (specifically SFTP).
I have read enough posts to go down the path of environment issues, so as you will see below, I hard referenced the location of the SFTP in the event of a PATH issue...
The only thing that I can think of is the IdentityFile. NOTE: I am putting this in the crontab for my user not root. So I understand that it should pickup on the id_dsa.pub that I have created (and that has already been shared with the server)..
I am not trying to do any funky expect commands to bypass the password, etc. I dont know why when run from the cron that it is skipping the SFTP line.
please see the code below.. and help is greatly appreciated.. thx
#!/bin/bash
export DATE=`date +%y%m%d%H%M%S`
export YYMMDD=`date +%y%m%d`
PDATE=$DATE
YDATE=$YYMMDD
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
FEED="~/Dropbox/"
USER="user"
HOST="host.domain.tld"
A="/tmp/5nPR45bH"
>${A}.file1${PDATE}
>${A}.file2${PDATE}
BYEbye ()
{
rm ${A}.file1${PDATE}
rm ${A}.file2${PDATE}
echo "Finished cleaning internal logs"
exit 0
}
echo "get -r *" >> ${A}.file1${PDATE}
echo "quit" >> ${A}.file1${PDATE}
eval mkdir ${FEED}${YDATE}
eval cd ${FEED}${YDATE}
eval /usr/bin/sftp -b ${A}.file1${PDATE} ${USER}#${HOST}
BYEbye
exit 0
Not an answer, just comments about your code.
The way to handle filenames with spaces is to quote the variable: "$var" -- eval is not the way to go. Get into the habit of quoting all variables unless you specifically want to use the side effects of not quoting.
you don't need to export your variables unless there's a command you call that expects to see them in the environment.
you don't need to call date twice because the YYMMDD value is a substring of the DATE: YYMMDD="${DATE:0:6}"
just a preference: I use $HOME over ~ in a script.
you never use the "file2" temp file -- why do you create it?
since your sftp batch file is pretty simple, you don't really need a file for it:
printf "%s\n" "get -r *" "quit" | sftp -b - "$USER#$HOST"
Here's a rewrite, shortened considerably:
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
FEED_DIR="$HOME/Dropbox/$(date +%Y%m%d)"
USER="user"
HOST="host.domain.tld"
mkdir "$FEED_DIR" || { echo "could not mkdir $FEED_DIR"; exit 1; }
cd "$FEED_DIR"
{
echo "get -r *"
echo quit
} |
sftp -b - "${USER}#${HOST}"

use external file with variables

The following is iptable save file, which I modified by setting some variables like you see below.
-A OUTPUT -o $EXTIF -s $UNIVERSE -d $INTNET -j REJECT
I also have a bash script which is defining this variables and should call iptables-restore with the save file above.
#!/bin/sh
EXTIF="eth0"
INTIF="eth1"
INTIP="192.168.0.1/32"
EXTIP=$(/sbin/ip addr show dev "$EXTIF" | perl -lne 'if(/inet (\S+)/){print$1;last}');
UNIVERSE="0.0.0.0/0"
INTNET="192.168.0.1/24"
Now I need to use
/sbin/iptables-restore <the content of iptables save file>
in bash script and somehow insert the text file on top to this script, so the variables will be initialized. Is there any way to do that?
UPDATE: even tried this
/sbin/iptables-restore -v <<-EOF;
$(</etc/test.txt)
EOF
Something like this:
while read line; do eval "echo ${line}"; done < iptables.save.file | /sbin/iptables-restore -v
or more nicely formatted:
while read line
do eval "echo ${line}"
done < iptables.save.file | /sbin/iptables-restore -v
The eval of a string forces the variable expansion stuff.
Use . (dot) char to include one shell script to another:
#!/bin/sh
. /path/to/another/script
In your shell script:
. /path/to/variable-definitions
/sbin/iptables-restore < $(eval echo "$(</path/to/template-file)")
or possibly
/sbin/iptables-restore < <(eval echo "$(</path/to/template-file)")

Resources