3

This work is being done on a test virtualbox machine

In my /root dir, i have created the following:
"/root/foo"
"/root/bar"
"/root/i have multiple words"

Here is the (relevant)code I currently have

  if [ ! -z "$BACKUP_EXCLUDE_LIST" ]
  then
    TEMPIFS=$IFS
    IFS=:
    for dir in $BACKUP_EXCLUDE_LIST
    do
      if [ -e "$3/$dir" ] # $3 is the backup source
      then
          BACKUP_EXCLUDE_PARAMS="$BACKUP_EXCLUDE_PARAMS --exclude='$dir'"
      fi    
    done
    IFS=$TEMPIFS
  fi


  tar $BACKUP_EXCLUDE_PARAMS -cpzf  $BACKUP_PATH/$BACKUP_BASENAME.tar.gz -C $BACKUP_SOURCE_DIR $BACKUP_SOURCE_TARGET

This is what happens when I run my script with sh -x

+ IFS=:
+ [ -e /root/foo ]
+ BACKUP_EXCLUDE_PARAMS= --exclude='foo'
+ [ -e /root/bar ]
+ BACKUP_EXCLUDE_PARAMS= --exclude='foo' --exclude='bar'
+ [ -e /root/i have multiple words ]
+ BACKUP_EXCLUDE_PARAMS= --exclude='foo' --exclude='bar' --exclude='i have multiple words'
+ IFS=  

# So far so good

+ tar --exclude='foo' --exclude='bar' --exclude='i have multiple words' -cpzf /backup/root/daily/root_20130131.071056.tar.gz -C / root
tar: have: Cannot stat: No such file or directory
tar: multiple: Cannot stat: No such file or directory
tar: words': Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors

# WHY? :(

The Check completes sucessfully, but the --exclude='i have multiple words' does not work.

Mind you that it DOES work when i type it in my shell, manually:

tar --exclude='i have multiple words' -cf /somefile.tar.gz /root

I know that this would work in bash when using arrays, but i want this to be POSIX.

Is there a solution to this?

Kaurin
  • 294
  • 1
  • 3
  • 9

2 Answers2

1

Consider this scripts; ('with whitespace' and 'example.desktop' is sample files)

#!/bin/bash

arr=("with whitespace" "examples.desktop")

for file in ${arr[@]}
do
    ls $file
done

This outputs as exactly as yours;

21:06 ~ $ bash test.sh 
 ls: cannot access with: No such file or directory
 ls: cannot access whitespace: No such file or directory
 examples.desktop

You can set IFS to '\n' character to escape white spaces on file names.

#!/bin/bash

arr=("with whitespace" "examples.desktop")

(IFS=$'\n';
    for file in ${arr[@]}
    do
        ls $file
    done
)

the output of the second version should be;

21:06 ~ $ bash test.sh 
 with whitespace
 examples.desktop
Muhammet Can
  • 1,304
  • 2
  • 16
  • 30
  • Unfortunately, I can't use arrays because I'm writing this script in dash :( – Kaurin Feb 01 '13 at 08:08
  • Oh I didn't see the notice on the original question. Sadly, I'm not experienced with dash. But you still have an iteration at line `for dir in $BACKUP_EXCLUDE_LIST`. Have you tried setting IFS (Internal Field Seperator) to "\n" character at `IFS=:` ? – Muhammet Can Feb 01 '13 at 17:48
  • David the H. from the LinuxQuestions forums helped me solve this. Check out my answer! – Kaurin Feb 01 '13 at 19:24
0

David the H. from the LinuxQuestions forums steered me in the right direction.

First of all, in my question, I did not make use IFS=: all the way through to the tar command Second of all, I included "set -f" for safety

BACKUP_EXCLUDE_LIST="foo:bar:i have multiple words"

# Grouping our parameters
if [ ! -z "$BACKUP_EXCLUDE_LIST" ]
then
  IFS=:         # Here we set our temp $IFS
  set -f        # Disable globbing
  for dir in $BACKUP_EXCLUDE_LIST
  do
    if [ -e "$3/$dir" ]  # $3 is the directory that contains the directories defined in $BACKUP_EXCLUDE_LIST
    then
      BACKUP_EXCLUDE_PARAMS="$BACKUP_EXCLUDE_PARAMS:--exclude=$dir"
    fi    
  done
fi

# We are ready to tar

tar $BACKUP_EXCLUDE_PARAMS \
  -cpzf  "$BACKUP_PATH/$BACKUP_BASENAME.tar.gz" \
  -C "$BACKUP_SOURCE_DIR" \
  "$BACKUP_SOURCE_TARGET"
unset IFS       # our custom IFS has done it's job. Let's unset it!
set +f          # Globbing is back on

I advise against using the TEMPIFS variable, like I did, because that method does not set the IFS back correctly. It's best to unset IFS when you are done with it

Kaurin
  • 294
  • 1
  • 3
  • 9