Question

I have a simple question about using variables as inputs to a command in a Bash script. I would like to write a script that automatically copies certain contents of a directory, foo, to an embedded computer connected over ssh in another directory, bar.

In other words, I want to turn the following command into an easier to maintain script:

ssh -r /foo/{file1,file2,dir1,*.h,*.hpp,*.c,*.cpp} uname@1.1.1.1:~/bar

So far, I have the following:

#!/bin/bash

SOURCE='/foo';
FILES='{file1,file2,dir1,*.h,*.hpp,*.c,*.cpp}';
DESTINATION='uname@1.1.1.1:~/bar';

set -x
scp -r $SOURCE/$FILES  $DESTINATION
set +x

However, this gets executed as:

ssh -r '/foo/{file1,file2,dir1,*.h,*.hpp,*.c,*.cpp}' 'uname@1.1.1.1:~/bar'

I'm sure I am using the wrong kinds of quotes or parenthesis somewhere, but I feel like I've tried everything. Thanks to anyone who can help a newbie out. :)

Was it helpful?

Solution

The manual would tell you that Brace expansion is performed before any other expansions ...

I don't think that you have any option but to use eval here if you want to make use of variables in the command:

SOURCE='/foo';
FILES='{file1,file2,dir1,*.h,*.hpp,*.c,*.cpp}';
FILELIST="$(eval echo "${SOURCE}"/"${FILES}")"

and later say:

scp -r "$FILELIST"  $DESTINATION

OTHER TIPS

If you put the braces or the *s inside quotes they will not be expanded by the shell. So, use:

scp -r "$SOURCE/"{file1,file2,dir1,*.h,*.hpp,*.c,*.cpp}  $DESTINATION

If you really want to define the file list before calling scp, then use a bash array:

filelist=( "$SOURCE/"{file1,file2,dir1,*.h,*.hpp,*.c,*.cpp} )

scp -r "${filelist[@]}" $DESTINATION

Here, filelist is an array and "${filelist[@]}" is bash's special incantation to return each filename in the list as a separate argument to scp.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top