0

I have the following bash array:

IGNORED_DIRS=(
    "vendor"
    "node_modules"
    "bower_components"
    "tmp"
    "backup"
)

And I need this to be outputted in such a way:

tar -cpzf /var/backups/ --exclude="vendor" --exclude="node_modules" --exclude="bower_components" --exclude="tmp" --exclude="backup"

So far, I have tried the following:

for dir in ${IGNORED_DIRS[@]}
do
    EXCLUDES=$EXCLUDES" --exclude=\""$dir"\""
done

So that I would end up with a variable containing the exact exclude string. I thought I could simply do

tar -cpzf /var/backups/ $EXCLUDES

But that simply ignores all of the exclude flags. Has anyone got the solution for me?

3
  • It seems like I've found a solution. Substituting the EXCLUDES line with this EXCLUDES=$EXCLUDES" --exclude="$dir" " seems to fix the issue. So now there are no quotes surrounding the exclude directories anymore. Strange that his does work... Commented Feb 21, 2017 at 20:50
  • The above only works for trivial cases -- try a directory name with a space. Commented Feb 21, 2017 at 20:59
  • 1
    BTW -- all-caps variable names are used for environment variables and shell builtins with meaning to the operating system or shell, whereas lowercase names are reserved for application use; thus, using lowercase names for your own shell variables means you can't overwrite a variable with meaning to the operating system by mistake -- particularly important if you want your code to be compatible with future OS and shell releases. See relevant spec. Commented Feb 21, 2017 at 21:04

2 Answers 2

4

This is covered in detail in BashFAQ #50. To summarize a solution:

extra_args=( )
for dir in "${IGNORED_DIRS[@]}"; do
    extra_args+=( --exclude="$dir" )
done

tar -cpz "${extra_args[@]}" -f /var/backups/
Sign up to request clarification or add additional context in comments.

2 Comments

Awesome answer.
Or, simpler, tar -cpz "${IGNORED_DIRS[@]/#/--exclude=}" -f /var/backups.
1

Modifying @favoretti's response, use (..) to collect the array and ${array[@]} to expand the array into items, rather than joining into one string.

IGNORED_DIRS=(
    "vendor"
    "node_modules"
    "bower_components"
    "tmp"
    "backup"
)

for dir in "${IGNORED_DIRS[@]}"
do
    EXCLUDES=("${EXCLUDES[@]}" --exclude="$dir")
done

tar -cf /var/backup "${EXCLUDES[@]}"

5 Comments

Primarily it needs ${EXCLUDES[@]} in the right spot in the tar command itself. Whether bash syntax is correct or less correct.
Thanks so much guys. Learning a lot!
GNU tar is flexible on the point, but it goes beyond POSIX spec in that. (Though admittedly, --exclude is out-of-spec as well).
re: options-before-positional-arguments, see POSIX utility syntax guidelines, guideline #9.
@JoshuaGoldberg, do you mind if I make the minimum necessary edits to fix the bugs?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.