para lista de pastas do loop sem expansão

2

Eu tento gerar uma linha de comando para um script de backup no bash shell.

Exemplo simples:

EXCLUDES="/home/*/.cache/* /var/cache/* /var/tmp/* /var/lib/lxcfs/cgroup/*"; 
for FOLDER in $EXCLUDES; do printf -- '--exclude %b\n' "$FOLDER" ; done

Deve resultar em:

--exclude '/home/*/.cache/*' --exclude '/var/cache/*' --exclude '/var/tmp/*' --exclude '/var/lib/lxcfs/cgroup/*'

Mas o problema é que as pastas são expandidas do shell. Eu tentei muitos exemplos com echo / printf / quote / IFS ... mas sem o resultado correto.

Qualquer maneira de corrigir isso?

    
por Thomas 03.07.2018 / 20:08

1 resposta

4

Sempre que você tiver que especificar uma lista de nomes de caminho ou nomes de caminho com nome de arquivo globs, ou apenas uma lista que você pretende passar por cima e / ou usar como lista de argumentos para algum comando, use uma matriz.

Se você não usar uma matriz, mas uma string, você não poderá processar coisas com espaços (porque você usa espaços como o delimitador na string). Isso também dificulta o loop do conteúdo da string, já que você terá que invocar a divisão de palavras (não citando a expansão da variável). Mas isso também fará com que a globalização de nomes de arquivo aconteça, a menos que você desative explicitamente isso com set -f .

Na maioria dos shells, mesmo em /bin/sh , use uma matriz. Em sh , use a matriz de parâmetros posicionais ( $@ ).

Para bash , use uma matriz de strings entre aspas, como

excludes=( '/home/*/.cache/*'
           '/var/cache/*'
           '/var/tmp/*'
           '/var/lib/lxcfs/cgroup/*' )

Então,

rsync_opts=( --verbose --archive )
for excl in "${excludes[@]}"; do
    rsync_opts+=( --exclude="$excl" )
done

Mais tarde,

rsync "${rsync_opts[@]}" source/ target

Observe que a cotação é importante em todas as expansões de variáveis acima. A expansão "${array[@]}" (assim como "$@" abaixo) resulta em uma lista de elementos citados individualmente da matriz em questão (mas apenas se forem citados em duplicado!).

Para qualquer /bin/sh shell:

set -- '/home/*/.cache/*'  \
       '/var/cache/*'      \
       '/var/tmp/*'        \
       '/var/lib/lxcfs/cgroup/*'

for excl do
    set -- "$@" --exclude="$excl"
    shift
done
set -- --verbose --archive "$@"

rsync "$@" source/ target
    
por 03.07.2018 / 20:22

Tags