Expansão da variável dentro de aspas simples em um comando no Bash

Eu quero executar um comando de um script de shell bash que tem aspas simples e alguns outros comandos dentro das aspas simples e uma variável.

por exemplo, repo forall -c '....$variable'

Nesse formato, $ é escapado e a variável não é expandida.

Eu tentei as seguintes variações, mas elas foram rejeitadas:

 repo forall -c '...."$variable" ' repo forall -c " '....$variable' " " repo forall -c '....$variable' " repo forall -c "'" ....$variable "'" 

Se eu replace o valor no lugar da variável, o comando será executado muito bem.

Por favor me diga onde estou indo errado.

    Dentro de aspas simples tudo é preservado literalmente, sem exceção.

    Isso significa que você precisa fechar aspas, inserir algo e, em seguida, redigitar novamente.

     'before'"$variable"'after' 'before'"'"'after' 'before'\''after' 

    Como você pode verificar, cada uma das linhas acima é uma única palavra para o shell. A concatenação de cordas é feita simplesmente por justaposição. Aspas (aspas simples ou duplas, dependendo da situação) são usadas para desabilitar a interpretação de vários caracteres especiais, como espaço em branco, $ ; … Para um bom tutorial sobre citações, veja a resposta de Mark Reed. Também relevante: quais personagens precisam ser escapados no bash?

    Não concatenar cadeias de caracteres interpretadas por um shell

    Você deve absolutamente evitar construir comandos shell concatenando variables. Essa é uma idéia ruim semelhante à concatenação de fragments SQL (injeção de SQL!).

    Geralmente, é possível ter espaços reservados no comando e fornecer o comando junto com variables ​​para que o receptor possa recebê-los da lista de argumentos de invocação.

    Por exemplo, o seguinte é muito inseguro. NÃO FAÇA ISSO

     script="echo \"Argument 1 is: $myvar\"" /bin/sh -c "$script" 

    Se o conteúdo de $myvar não for confiável, aqui está uma exploração:

     myvar='foo"; echo "you were hacked' 

    Em vez da invocação acima, use argumentos posicionais. A seguinte invocação é melhor – não é explorável:

     script='echo "arg 1 is: $1"' /bin/sh -c "$script" -- "$myvar" 

    Observe o uso de caracteres únicos na atribuição ao script , o que significa que é considerado literalmente, sem expansão de variável ou qualquer outra forma de interpretação.

    O comando repo não pode se importar com o tipo de cotação obtido. Se você precisar de expansão de parâmetro, use aspas duplas. Se isso significa que você precisa fazer backslash em muitas coisas, use aspas simples para a maioria delas e, em seguida, divida-as e entre em duplas para a parte em que você precisa que a expansão aconteça.

     repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff' 

    Explicação segue, se você estiver interessado.

    Quando você executa um comando a partir do shell, o que esse comando recebe como argumentos é uma matriz de seqüências terminadas em nulo. Essas cadeias podem conter absolutamente qualquer caractere não nulo.

    Mas quando o shell está construindo esse array de strings a partir de uma linha de comando, ele interpreta alguns caracteres especialmente; isso é projetado para tornar os comandos mais fáceis (na verdade, possíveis) de digitar. Por exemplo, os espaços normalmente indicam o limite entre as cadeias na matriz; por essa razão, os argumentos individuais são às vezes chamados de “palavras”. Mas um argumento pode, no entanto, ter espaços nele; você só precisa de um jeito de dizer ao shell que é o que você quer.

    Você pode usar uma barra invertida na frente de qualquer caractere (incluindo espaço ou outra barra invertida) para dizer ao shell para tratar o caractere literalmente. Mas enquanto você pode fazer algo assim:

    echo \"Thank\ you.\ \ That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

    … pode ficar cansativo. Então o shell oferece uma alternativa: aspas. Estes vêm em duas variedades principais.

    Aspas duplas são chamadas de “cotações de agrupamento”. Eles impedem que curingas e aliases sejam expandidos, mas na maioria das vezes eles são para include espaços em uma palavra. Outras coisas como expansão de parâmetros e comandos (o tipo de coisa sinalizada por um $ ) ainda acontecem. E, claro, se você quiser um aspas duplas dentro das aspas duplas, é necessário invertê-lo:

    echo "\"Thank you. That'll be \$4.96, please,\" said the cashier"

    Aspas simples são mais draconianas. Tudo entre eles é tomado literalmente, incluindo barras invertidas. Não há absolutamente nenhuma maneira de obter uma aspa simples literal dentro de aspas simples.

    Felizmente, aspas no shell não são delimitadores de palavras ; por si mesmos, eles não terminam uma palavra. Você pode entrar e sair de citações (ou entre diferentes tipos de citações) dentro da mesma palavra para obter o resultado desejado:

    echo '"Thank you. That'\''ll be $4.96, please," said the cashier'

    Então, isso é mais fácil – muito menos barras invertidas, embora a sequência de aspas simples, barra invertida literal, aspas simples e sequência de aspas abertas demorem para se acostumar.

    Os shells modernos adicionaram outro estilo de cotação não especificado pelo padrão POSIX, no qual a aspa simples à esquerda é prefixada com um cifrão. As strings assim citadas seguem convenções similares para string literais na linguagem de programação ANSI C, e são, portanto, algumas vezes chamadas de “strings ANSI” e o par $'' “ANSI quotes”. Dentro de tais cadeias, o conselho acima sobre as barras invertidas sendo tomadas literalmente não se aplica mais. Em vez disso, eles se tornam especiais novamente – não apenas você pode include uma aspa ou barra invertida literal ao include uma barra invertida nela, mas também expande os escapes de caracteres ANSI C (como \n para uma nova linha, \t para tabulação e \xHH para o caractere com o código hexadecimal HH ). Caso contrário, no entanto, eles se comportam como sequências com aspas simples: nenhum parâmetro ou substituição de comando ocorre:

     echo $'"Thank you. That\'ll be $4.96, please," said the cashier' 

    O importante é notar que a única string recebida como argumento para o comando echo é exatamente a mesma em todos esses exemplos. Depois que o shell terminar de analisar uma linha de comando, não há como o comando ser executado para informar o que foi citado como. Mesmo se quisesse.

    EDIT: (De acordo com os comentários em questão 🙂

    Eu tenho olhado para isso desde então. Eu tive a sorte de ter repo por aí. Ainda não está claro para mim se você precisa colocar seus comandos entre aspas simples à força. Eu olhei para a syntax repo e eu não acho que você precisa. Você poderia usar aspas duplas em torno do seu comando e, em seguida, usar as aspas simples e duplas necessárias, desde que escape das duplas.

    Abaixo está o que funcionou para mim –

    QUOTE="'" hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"

    Isso funciona para você?

     eval repo forall -c '....$variable' 

    Variáveis ​​podem conter aspas simples.

     myvar=\'....$variable\' repo forall -c $myvar