Shell Script: criando uma variável com opções dentro

10

Eu tenho um comando rsync com os seguintes parâmetros:

rsync -avz --{partial,stats,delete,exclude=".*"}

Eu quero colocar esses parâmetros dentro de uma variável para reutilizá-lo depois no script. Algo parecido com isto:

#!/bin/bash
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}
$VAR /dir1 /dir2

Eu tentei com aspas simples, parênteses, sem sucesso.

    
por Kellyson 24.02.2018 / 17:43

3 respostas

13

Colocar um comando complexo em uma variável nunca é uma abordagem recomendada. Veja BashFAQ / 050 - Estou tentando colocar um comando em uma variável, mas os casos complexos sempre falham!

Sua exigência se torna realmente simples, se você decidir usar uma função em vez de uma variável e passar argumentos para ela.

Algo como

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --{partial,stats,delete,exclude=".*"} "$@"
}

e agora passa os argumentos necessários para ele como

rsync_custom /dir1 /dir2

A definição da função é bastante simples de uma forma, primeiro verificamos a contagem do argumento de entrada usando a variável $# que não deveria ser zero. Nós jogamos uma mensagem de erro dizendo que nenhum argumento é fornecido. Se houver argumentos válidos, "$@" representa os argumentos reais fornecidos para a função.

Se esta é uma função que você usaria com bastante frequência, por exemplo, em scripts / linha de comando, adicione-a aos arquivos de inicialização do shell, .bashrc , .bash_profile , por exemplo.

Ou, conforme observado, pode valer a pena expandir a expansão de chaves para separar argumentos para uma melhor legibilidade, pois

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --partial --stats --delete --exclude=".*" "$@"
}
    
por 24.02.2018 / 17:49
5
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

Isso tenta executar o comando -avz com os argumentos --partial , --stats etc .. e com VAR definido como rsync no ambiente.

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

O formulário citado não funciona porque as chaves não são expandidas entre aspas, e não dentro das atribuições, e nem são expandidas depois que uma variável é expandida.

Se você precisar armazenar argumentos de linha de comando em uma variável, use uma matriz:

args=(rsync -avz --{partial,stats,delete,exclude=".*"})

Agora, "${args[@]}" expandirá para rsync , -avz , --partial , etc. como palavras distintas.

Os arrays também permitem que você anexe opções à lista, condicionalmente, se necessário, para que você possa, por exemplo:

args=(this that)
if something ; then
    args+=(another_arg)
fi
"$cmd" "${args[@]}"
    
por 24.02.2018 / 20:37
1

Você pode pelo menos salvar as opções parcialmente em uma variável:

opts=$(echo --{ignore-case,word-regexp,count,exclude='"sys*.*"'})

O teste é importante porque o mascaramento pode ser difícil:

echo $opts
--ignore-case --word-regexp --count --exclude="sys*"

grep $opts bytes *.log 

Como existem várias alternativas, como usar o histórico, usando um alias, usando uma função, não há nenhum caso de uso óbvio que eu possa imaginar. Raramente há uma opção complexa de compartilhamento entre programas diferentes, portanto, para uma solução ad-hoc para o shell interativo, o aliasing parece ser o melhor caminho:

alias cgrep='grep --ignore-case --word-regexp --count --exclude="sys*"'
cgrep bytes *.log

Sua amostra

VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

não funciona, porque a atribuição é endet no primeiro espaço em branco. Você tem que mascarar os espaços em branco:

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

uma coisa muito perigosa para testes, com essa opção --delete, não é? Como as opções podem conter novamente "," e aspas simples, o mascaramento pode ficar difícil muito em breve. Eu iria para um alias ou confiar na história.

Um alias pode ser armazenado no arquivo ~ / .bashrc para uso contínuo em várias sessões. As funções podem ser armazenadas no bashrc também, mas você só precisa delas, se quiser manipular parâmetros, passados para a função a ser avaliada.

    
por 24.02.2018 / 19:53