Como fazer argumentos opcionais que podem ser nomes de arquivos contendo espaços

3

Eu pouparei você de todo o comando multi-line duplicity , mas o que eu quero saber é se é possível arrumar uma série de argumentos em um script como este:

--exclude "$2/${4:-__nosuchfiles__}" --exclude "$2/${5:-__nosuchfiles__}" ...

o principal é que $4 , $5 , ... são nomes que geralmente contêm espaços. A presente formulação funciona, mas à custa desses padrões feios para __nosuchfiles__ para não excluir nada se o conjunto de critérios de exclusão for menor que o número de exclusões passadas. É também um hack em que alguém pode criar uma pasta chamada __nosuchfiles__ , e que há um limite no número de exclusões que ele pode manipular.

O que eu gostaria, é definir

EXCLUDES='--exclude "Path 1" --exclude "Path 2"'

com quantos --exclude eu precisar, nenhum com muitos e, em seguida, substituirei $EXCLUDES em uma linha de comando de duplicidade como:

duplicity $STUFF $EXCLUDES $SOURCE $DESTINATION

é claro, não funciona quando as exclusões especificam nomes contendo espaços, e não consigo elaborar nenhuma formulação para definir e usar esse conjunto de exclusões no próprio script. (Pontos de bônus se qualquer resposta também lida com EXCLUDES="" para não significar exclusões).

Sim, eu sei que poderia usar --exclude-filelist da duplicidade, mas gostaria de saber se há uma solução geral que não dependa do comando convenientemente capaz de ler uma lista de nomes de um arquivo em vez de a linha de comando. Observe também o prefixo de $2/ em todos os caminhos de exclusão.

    
por nigel222 08.09.2016 / 12:20

2 respostas

1

Você precisa criar a linha de comando de duplicidade usando uma matriz em vez de uma concatenação de cadeia simples. Em seguida, você pode usar a sintaxe "${array[@]}" para fornecer o conteúdo da matriz à duplicidade como argumentos individuais (possivelmente contendo espaço). Isso tira você do negócio de ter que pensar em fugir de espaços ou outros caracteres incomuns.

Para ver como isso funciona sem realmente chamar a duplicidade, você pode usar um script simples que imprime seus argumentos em linhas separadas, como esta:

#!/bin/bash

printf "BEGIN\n"

for x in "$@"
do
  printf "ARG: $x\n"
done

printf "END\n"

Eu salvei isso como args.sh .

Agora, precisamos criar um comando usando uma matriz, assim:

#!/bin/bash

if test -z "$1"
then
  printf "Need at least one argument"
  exit 1
fi

prefix=$1
shift

for arg in "$@"
do
    args+=("--exclude")
    args+=("$prefix/$arg")
done

./args.sh "${args[@]}"

Em ação, isso funciona da seguinte maneira:

$ ./801811.sh foo bar "baz quux"
BEGIN
ARG: --exclude
ARG: foo/bar
ARG: --exclude
ARG: foo/baz quux
END

Você precisará fazer mais para configurar sua linha de comando de duplicidade, já que também precisa considerar $STUFF e $DESTINATION , mas eles podem ser tratados da mesma maneira, adicionando elementos à matriz args com args+=("whatever") , antes ou depois de adicionar as exclusões, conforme apropriado. Então, no final, basta ligar para duplicity "${args[@]}" .

    
por 09.09.2016 / 06:42
0

Os espaços são uma exceção aqui, já que a expansão está entre aspas. Se nós chamarmos um programa do shell assim:

program "$foo_path/$bar_name"

recebe um único argumento, não importa o que seja foo_path ou bar_name .

Agora vamos dar uma olhada:

--exclude "$2/${4:-__nosuchfiles__}" 

Aqui, você deseja apagar todo o par de argumentos se 4 estiver em branco ou não existir, gerando a solução:

${4:+--exclude} ${4:+"$2/$4"}

O operador de substituição de parâmetro :+ é o que você precisa: "se estiver em branco ou não definido, substitua nada, caso contrário, substitua uma alternativa". Aplicamos isso individualmente ao --exclude e seu argumento.

As ferramentas que usam uma implementação getopt (ou, de outra forma, hackear o suporte) podem obter --exclude=ARG e --exclude ARG . Se duplicity funcionar dessa maneira, podemos tirar proveito disso:

${4:+"--exclude=$2/$4"}

Programa de demonstração completo test.sh :

#!/bin/bash

myargs()
{
  for x in "$@" ; do printf "<%s>\n" "$x"; done
}

myargs ${1:+--foo-opt} ${1:+"x $1 x"}

Execuções:

$ ./test.sh
$ ./test.sh ""      # blank treated like missing?
$ ./test.sh abc
<--foo-opt>
<x abc x>
$ ./test.sh "ab c"
<--foo-opt>
<x ab c x>
    
por 09.10.2016 / 16:43