Bash: bad substitution

I was working on a bash script that uploads a file via sftp and appends a suffix to the filename. The suffix, in this specific case, should have been the date in %y-%m-%d_%H%M%S format.

I’m still a newbie with bash scripting and I used this command to upload and rename the file:

put $file $remote_dest_dir/$remote_filename${date +"%y-%m-%d_%H%M%S"}

Bash complained about a “bad substitution” on that line.

Curly braces are used for different types of parameter expansion and one of the simplest involves the expansion of the value of a variable. The date command inside the braces it’s not a valid parameter or any other expansion, so the shell complains.

I guess that what I really needed was a substitution:

$(date +"%y-%m-%d_%H%M%S")

I replaced the curly braces with regular parenthesis and everything worked like a charm.

Pass a bash array as an argument

I have a bash script in which I’m using an array to get a list of files and I needed to pass the content of this array as an argument, to send an email to some users.

This is the array:

RAW_LIST="$(echo "ls -1 /download")"
declare -a LIST
readarray -t LIST <<<"${RAW_LIST}"

This is how I passed the array to bash:

printf %"s\n"  "${LIST[@]:1}" | /bin/mail -s "$SUBJECT" "$EMAIL"

Trailing :1 in the array will consider all the elements after element [0] as, in this specific case, it'd be ls -1, pretty useless sending it to the user.

Script: receive files via SFTP

In the past days I had to write a script to download files from a remote server using an SFTP connection; this script will be run by cron.

The goal was to download the files on my server and delete them on the remote machine after being downloaded.

I used an array to get the list of the current files on the remote server and a for-loop to download them.

#!/bin/bash
# 
# 20180801
#
# Receive files via SFTP


LOGFILE=/var/tmp/receivefiles.$(date -I).log
echo "START: $(date)" >>$LOGFILE

# Connection data
HOST='XXX.XXX.XXX.XXX'
PORT='22'
USER='mashiny'

# Where to download files
cd /home/mashiny/download

# File list
LIST_RAW="$(echo "ls -1 /out" | sftp -oPort=$PORT $USER@$HOST 2>/dev/null)"
declare -a LIST
readarray -t LIST <<<"${LIST_RAW}"

if   [[ "${#LIST[@]}" -lt 1 ]]; then
    echo "Unknown error in SFTP connection" >>$LOGFILE
    exit 1
elif [[  "${#LIST[@]}" -lt 2 ]]; then
    echo "No files to download" >>$LOGFILE
    exit 0
fi

# Connection via SFTP and download files
for FILE in "${LIST[@]:1}"
do
    # Download
    echo "get $FILE" | sftp -oPort=$PORT $USER@$HOST &>/dev/null
    [ $? -ne 0 ] && echo "$FILE download failed" >>$LOGFILE && continue
    echo "$FILE downloaded" >>$LOGFILE

    # Delete on remote dir
    echo "rm $FILE" | sftp -oPort=$PORT $USER@$HOST &>/dev/null
    [ $? -ne 0 ] && echo "$FILE not removed" >>$LOGFILE && continue
    echo "$FILE removed" >>$LOGFILE
done

echo "END:   $(date)" >>$LOGFILE
exit 0