Bash: linha de comando com argumentos opcionais

7

Estou executando esse tipo de código:

#!/usr/bin/env bash
set -u
exclude1='--exclude=/path/*'
exclude2='--exclude=/path with spaces/*'
exclude3=''        # any 'exclude' can be empty
tar -czf backup.tgz "$exclude1" "$exclude2" "$exclude3" 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

Quando executo este código, recebo este erro:

tar: : Cannot stat: No such file or directory

Isso ocorre porque "$ exclude3" é traduzido como um argumento vazio. Exatamente como se eu fizesse isso:

tar -czf backup.tgz "$exclude1" "$exclude2" ''

Uma maneira de evitar esse erro é remover as aspas duplas em torno de $ excludeX. Mas isso é um problema se $ excludeX contiver algum espaço ou outros caracteres estranhos.

Outra maneira seria usar eval , mas como preciso manter as aspas duplas, não vejo como suprimir as aspas E os argumentos vazios quando necessário.

A única solução que encontrei é construir a linha de comando com concatenação de strings:

CMD='tar -czf backup.tgz'
if [[ -n "$exclude1" ]]; then CMD+=" \"$exclude1\" "; fi
if [[ -n "$exclude2" ]]; then CMD+=" \"$exclude2\" "; fi
if [[ -n "$exclude3" ]]; then CMD+=" \"$exclude3\" "; fi
eval $CMD 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

Alguém tem uma ideia mais inteligente?

    
por Gregory MOUSSAT 28.04.2013 / 00:36

3 respostas

7
tar -czf backup.tgz "$exclude1" "$exclude2" ${exclude3+"$exclude3"} 2>&1

${exclude3+"$exclude3"} se expande para nada, se $exclude3 não estiver definido e para "$exclude3" , se estiver definido.

(e semelhantemente para as outras variáveis potencialmente não definidas).

Note que existe uma diferença entre uma variável não definida e uma variável que é definida para a string vazia, então você deve usar

unset exclude3

em vez de

exclude3=''
    
por 28.04.2013 / 01:36
7

Como você está trabalhando no bash, use uma matriz .

excludes=()
excludes+=('--exclude=/path/*')
…
tar -czf backup.tgz "${excludes[@]}"

Se você tiver uma entrada opcional em alguma variável, adicione-a em uma condicional.

if [[ -n $exclude_or_empty ]]; then excludes+=("$exclude_or_empty"); fi
    
por 28.04.2013 / 01:43
1

Isso funciona para mim no bash no Ubuntu, mas eu não tenho idéia, seja compatível com POSIX / compatível:

tar -czf backup.tgz \
$(if "$exclude1" != ""); then echo "$exclude1"; fi
$(if "$exclude2" != ""); then echo "$exclude3"; fi
$(if "$exclude3" != ""); then echo "$exclude3"; fi
    
por 15.12.2016 / 19:46