2

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} [email protected]:~/bar

So far, I have the following:

#!/bin/bash

SOURCE='/foo';
FILES='{file1,file2,dir1,*.h,*.hpp,*.c,*.cpp}';
DESTINATION='[email protected]:~/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}' '[email protected]:~/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. :)

2 Answers 2

2

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
Sign up to request clarification or add additional context in comments.

1 Comment

Well you certainly got me closer to a solution. With your approach the FILELIST got expanded, but the arguments to scp were still appearing inside single quotes so in my case (where /foo is the current directory ., and DESTINATION is referencing the home directory, ~, those symbols weren't getting parsed. I had to modify your solution to read scp -r $(eval echo "$FILELIST") $(eval echo $DESTINATION) to work. Thanks for your help!
1

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.

1 Comment

I ended up using something closer to devnull's approach, but thanks for your help and teaching me something new about bash arrays! =)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.