Como usar variáveis ​​entre aspas simples

11

Eu tenho um aplicativo que leva como atributos de entrada entre aspas duplas incorporadas entre aspas simples. Tomemos, por exemplo, este comando certo:

command -p 'cluster="cl1"'

Para automatizá-lo, criei um arquivo bash usando $CLUSTERcomo variável. Como deve ser o meu comando? Em outras palavras, o que devo colocar em vez de cl1?

Observe que, se eu modifiquei o comando acima, ele não será aceito. Por exemplo: command -p "cluster=cl1"não é aceito

Mohamad-Jaafar NEHME
fonte
2
CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"
mikeserv
Outra possibilidade (se você preferir armazenar clisem aspas dentro da CLUSTERvariável):CLUSTER='cl1'; command -p 'cluster="'"$CLUSTER"'"'
jimmij
Finalmente, encontrei a resposta certa. Obrigado @jimmij.
Mohamad-Jaafar NEHME

Respostas:

8

Parece que o seu comando talvez esteja configurando variáveis ​​de ambiente com base em argumentos dados na linha de comando. Pode ser que você possa fazer:

CLUSTER=cl1; cluster=$CLUSTER command

... e defina seu ambiente para isso na chamada.

Caso contrário, as aspas do shell normalmente delimitam argumentos ou escapam a outros caracteres especiais do shell da interpretação do shell. Você pode conter (e, portanto, escapar) diferentes tipos de aspas dentro de outros tipos com base em várias regras:

  • "''''" - uma string de aspas simples pode conter qualquer número de aspas.
  • "\""- uma \barra invertida pode escapar "de aspas dentro de uma "cadeia de caracteres entre aspas.
    • Nesse contexto, uma \\barra invertida também escapa a si mesma, ao \$token de expansão e às \nlinhas de ew, conforme observado abaixo, mas, de outra forma, é tratado literalmente.
  • "${expand} and then some"- uma string de aspas simples pode conter uma $expansão de shell interpretada .
  • '"\'- uma 'cadeia de caracteres entre aspas pode conter qualquer caractere além de 'aspas.
  • \- uma barra invertida não citada escapará a qualquer caractere a seguir para interpretação literal - até outra barra invertida - exceto uma linha de \new.
    • Em um \\ncaso de linha de ewline, a \barra invertida e a linha de \new são completamente removidas do comando interpretado resultante.
  • ${parameter+expand "$parameter"}- cotações resultantes de uma expansão de shell quase nunca servem como marcadores delimitadores, exceto em alguns casos especiais. Não vou me aventurar a descrevê-los mais aqui.

Considero estranho que qualquer aplicativo interprete aspas em seus argumentos de linha de comando. Tal prática não faz muito sentido, pelo menos para as conchas - o objetivo principal de uma citação é geralmente delimitar um argumento. Na invocação, no entanto, os argumentos estão sempre delimitados com \0NULcaracteres e, portanto, uma citação não pode ter muito objetivo.

Até mesmo um shell normalmente se preocupa em interpretar aspas em um de seus argumentos de chamada quando é chamado com um -ccomutador - o que indica que seu primeiro operando é na verdade um script de shell que deve ser executado na chamada. Este é um caso de entrada avaliada duas vezes .

Tudo isso dito, você pode fazer várias coisas para passar aspas literais por meio de argumentos na linha de comando. Por exemplo:

CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"

Como observei em um comentário anterior, você pode conter as "aspas dentro de uma expansão que é "citada.

CLUSTER=cl1; command -p "cluster=\"$CLUSTER\""

Você pode escapar a "com uma \barra invertida dentro da "string.

CLUSTER=cl1; command -p cluster='"'"$CLUSTER"'"'

Você pode alternar e concatenar os estilos de cotação para chegar ao resultado final desejado, como as notas de @jimmij acima .

CLUSTER=cl1; ( set -f; IFS=; command -p cluster=\"$CLUSTER\" )

Você pode desativar a geração e a $IFSdivisão do nome do arquivo - evitando assim a necessidade de citar $expansiontodos - e, portanto, apenas as aspas. Provavelmente é um exagero.

Por último, existe outro tipo de citação de shell que pode ser usado. Como observei anteriormente, a sh -c "$scriptlet"forma de invocação de shell geralmente é usada para fornecer o script de um shell na linha de comando. $scriptletPorém, quando fica complicado - como quando aspas devem conter outras aspas - pode ser vantajoso usar um documento aqui e, em sh -svez disso - onde o shell é instruído especificamente para atribuir todos os operandos a seguir aos parâmetros posicionais, como faria em um -ccaso e ainda assim também tirar o script stdin.

Se seu comando deve interpretar aspas dessa maneira, consideraria melhor se pudesse fazê-lo em uma entrada de arquivo. Por exemplo:

CLUSTER=cl1
command --stdin <<-SCRIPT
    cluster="$CLUSTER"
SCRIPT

Se você não citar o delimitador de a <<here-document, todo o seu conteúdo será tratado quase exatamente como se estivesse "entre aspas simples - exceto que "as aspas duplas não serão tratadas especialmente. E assim, se executarmos o acima com cat:

CLUSTER=cl1
cat <<-SCRIPT
        cluster="$CLUSTER"
SCRIPT

... imprime ...

cluster="cl1"
mikeserv
fonte
1

Como mikeserv escreveu:

 CLUSTER='"cl1"'; command -p "cluster=$CLUSTER" 

"Quote Double" cada literal que contenha espaços / metacharacters e cada expansão: "$var", "$(command "$var")", "${array[@]}", "a & b". Use 'single quotes'para código ou literal $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Consulte
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words

Gilles Quenot
fonte
Você está certo, obrigado. Mas e a automação? Suponha que eu queira ler CLUSTER? I vai ficar preso novamente com o mesmo problema: aspas simples dentro variável
Mohamad-Jaafar Nehme
@Moi - a automação não é grande coisa, embora você precise higienizar a variável de "caracteres - apenas o primeiro e o último devem ser suficientes. O verdadeiro problema aqui é que seu aplicativo interpreta aspas em um argumento. Interpretar uma citação em um argumento quase nunca é uma boa idéia, porque uma citação deve ser apenas um meio de delimitar um argumento - e na invocação esse delimitador é tratado por \0NULs em todos os casos. Provavelmente, existe uma maneira melhor de passar as informações que você deseja para o aplicativo? Como um command --'script=/path/to/some/file'ou algo assim?
precisa saber é o seguinte