Diferença entre aspas simples e duplas no Bash

Respostas:

579

Aspas simples não interpolam nada, mas as aspas duplas o fazem. Por exemplo: variáveis, backticks, certos \escapes, etc.

Exemplo:

$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")

O manual do Bash tem o seguinte a dizer:

3.1.2.2 Citações simples

Incluir caracteres entre aspas simples ( ') preserva o valor literal de cada caractere entre aspas. Uma aspas simples pode não ocorrer entre aspas simples, mesmo quando precedida por uma barra invertida.

3.1.2.3 Cotações duplas

Anexando caracteres entre aspas duplas ( ") preserva o valor literal de todos os caracteres entre as aspas, com exceção de $, `, \, e, quando a expansão história está habilitado, !. Os caracteres $e `mantêm seu significado especial entre aspas duplas (consulte Expansões do Shell ). A barra invertida mantém o seu significado especial apenas quando seguido por um dos seguintes caracteres: $, `, ",\ou nova linha. Nas aspas duplas, as barras invertidas que são seguidas por um desses caracteres são removidas. As barras invertidas que precedem os caracteres sem um significado especial não são modificadas. As aspas duplas podem ser citadas entre aspas duplas, precedendo-a com uma barra invertida. Se ativado, a expansão do histórico será executada, a menos que uma !aparição entre aspas duplas seja escapada usando uma barra invertida. A barra invertida anterior ao !não é removida.

Os parâmetros especiais *e @têm significado especial entre aspas duplas (consulte Expansão dos parâmetros do shell ).

Adam Batkin
fonte
41
Para quem não sabe o que "interpolar" significa: en.wikipedia.org/wiki/String_interpolation
Kolob Canyon
E quando você está usando um git_promptque o git fornece, eles sugerem usá-lo assim PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', git prompt , de acordo com isso não deve funcionar. Existe algo de especial nas PS#variáveis? ou por que funciona se não está fazendo a interpolação.
ekiim
@ekiim Esse texto exato é definido (inalterado) em PS1. Tente echo $PS1ver o que eu quero dizer. Mas PS1é avaliado antes de ser exibido (consulte a PROMPTINGseção na página de manual do bash). Para testar isso, tente PS1='$X'. Você não terá nenhum aviso. Em seguida, execute X=fooe de repente seu prompt é "foo" (havia PS1sido avaliado quando definido em vez de exibido, você ainda não teria nenhum prompt).
Adam Batkin 04/03/19
262

A resposta aceita é ótima. Estou fazendo uma tabela que ajuda na rápida compreensão do tópico. A explicação envolve uma variável simples a, bem como uma matriz indexada arr.

Se definirmos

a=apple      # a simple variable
arr=(apple)  # an indexed array with a single element

e então echoa expressão na segunda coluna, obteríamos o resultado / comportamento mostrado na terceira coluna. A quarta coluna explica o comportamento.

 # | Expression  | Result      | Comments
---+-------------+-------------+--------------------------------------------------------------------
 1 | "$a"        | apple       | variables are expanded inside ""
 2 | '$a'        | $a          | variables are not expanded inside ''
 3 | "'$a'"      | 'apple'     | '' has no special meaning inside ""
 4 | '"$a"'      | "$a"        | "" is treated literally inside ''
 5 | '\''        | **invalid** | can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
 6 | "red$arocks"| red         | $arocks does not expand $a; use ${a}rocks to preserve $a
 7 | "redapple$" | redapple$   | $ followed by no variable name evaluates to $
 8 | '\"'        | \"          | \ has no special meaning inside ''
 9 | "\'"        | \'          | \' is interpreted inside "" but has no significance for '
10 | "\""        | "           | \" is interpreted inside ""
11 | "*"         | *           | glob does not work inside "" or ''
12 | "\t\n"      | \t\n        | \t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13 | "`echo hi`" | hi          | `` and $() are evaluated inside ""
14 | '`echo hi`' | `echo hi`   | `` and $() are not evaluated inside ''
15 | '${arr[0]}' | ${arr[0]}   | array access not possible inside ''
16 | "${arr[0]}" | apple       | array access works inside ""
17 | $'$a\''     | $a'         | single quotes can be escaped inside ANSI-C quoting
18 | "$'\t'"     | $'\t'       | ANSI-C quoting is not interpreted inside ""
19 | '!cmd'      | !cmd        | history expansion character '!' is ignored inside ''
20 | "!cmd"      | cmd args    | expands to the most recent command matching "cmd"
21 | $'!cmd'     | !cmd        | history expansion character '!' is ignored inside ANSI-C quotes
---+-------------+-------------+--------------------------------------------------------------------

Veja também:

codeforester
fonte
1
A resposta aceita diz no final, The special parameters * and @ have special meaning when in double quotesentão como é que "*"resulta *?
anddero
2
@ Karl-AnderoMere, porque eles não são expandidos como parâmetros nesse caso. "$@"e "$*"são expansões de parâmetros. "@"e "*"não é.
Charles Duffy
@CharlesDuffy Obrigado, agora faz sentido!
precisa saber é o seguinte
3
Número 9, echo "\'"me devolve \'.
MaxGyver 16/10/19
@ MaxGyver: obrigado por apontar. Eu atualizei a resposta.
codeforester
233

Se você estiver se referindo ao que acontece quando ecoar algo, as aspas simples literalmente ecoarão o que você tem entre elas, enquanto as aspas duplas avaliarão variáveis ​​entre elas e produzirão o valor da variável.

Por exemplo, isso

#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'

vai dar o seguinte:

double quotes gives you sometext
single quotes gives you $MYVAR
igualmente
fonte
11

Outros explicaram muito bem e só querem dar com exemplos simples.

Aspas simples podem ser usadas em torno do texto para impedir que o shell interprete caracteres especiais. Cifrões, espaços, e comercial, asteriscos e outros caracteres especiais são todos ignorados quando colocados entre aspas simples.

$ echo 'All sorts of things are ignored in single quotes, like $ & * ; |.' 

Isso dará o seguinte:

All sorts of things are ignored in single quotes, like $ & * ; |.

A única coisa que não pode ser colocada entre aspas simples é uma aspas simples.

As aspas duplas atuam de maneira semelhante às aspas simples, exceto que as aspas duplas ainda permitem que o shell interprete sinais de dólar, aspas e barras invertidas. Já se sabe que as barras invertidas impedem que um único caractere especial seja interpretado. Isso pode ser útil entre aspas duplas se um cifrão precisar ser usado como texto em vez de como uma variável. Ele também permite que aspas duplas sejam escapadas para que não sejam interpretadas como o final de uma sequência de caracteres citada.

$ echo "Here's how we can use single ' and double \" quotes within double quotes"

Isso dará o seguinte:

Here's how we can use single ' and double " quotes within double quotes

Também pode ser notado que o apóstrofo, que de outra forma seria interpretado como o início de uma seqüência de caracteres citada, é ignorado entre aspas duplas. As variáveis, no entanto, são interpretadas e substituídas por seus valores entre aspas duplas.

$ echo "The current Oracle SID is $ORACLE_SID"

Isso dará o seguinte:

The current Oracle SID is test

As aspas anteriores são totalmente diferentes das aspas simples ou duplas. Em vez de serem usadas para impedir a interpretação de caracteres especiais, as aspas na verdade forçam a execução dos comandos que eles incluem. Depois que os comandos incluídos são executados, sua saída é substituída no lugar das aspas na linha original. Isso ficará mais claro com um exemplo.

$ today=`date '+%A, %B %d, %Y'`
$ echo $today 

Isso dará o seguinte:

Monday, September 28, 2015 
Sree
fonte
3

Existe uma distinção clara entre o uso de ' 'e " ".

Quando ' 'é usado em torno de qualquer coisa, não há "transformação ou tradução" feita. É impresso como está.

Com " ", o que quer que esteja ao redor, é "traduzido ou transformado" em seu valor.

Por tradução / transformação, quero dizer o seguinte: Qualquer coisa entre aspas simples não será "traduzida" para seus valores. Eles serão tomados como estão entre aspas. Exemplo:, a=23então echo '$a'produzirá $ana saída padrão. Considerando que echo "$a"irá produzir 23na saída padrão.

a_r
fonte
1
O que você quer dizer com "tradução" ou "transformação"?
Nico Haase
Essa resposta é bastante confusa e não adiciona nada além das boas respostas existentes.
precisa saber é o seguinte
2
Essa foi uma resposta concisa e curta, na minha opinião, sem ser excessivamente prolixo e fácil de entender. Ao dizer tradução / transformação, elas significam aspas duplas expandirão a variável, onde aspas simples não expandirão a variável.
B_e_n_n_y_ 9/04/19
1
Sim, esta é a melhor resposta. Essa deve ser a resposta aceita.
precisa
3

Como essa é a resposta de fato ao lidar com aspas bash, acrescentarei mais um ponto esquecido nas respostas acima, ao lidar com os operadores aritméticos no shell.

O bashshell suporta duas formas de operação aritmética, uma definida pelo letcomando interno e pelo $((..))operador. O primeiro avalia uma expressão aritmética, enquanto o último é mais uma declaração composta.

É importante entender que a expressão aritmética usada letsofre expansão de nome de caminho e divisão de palavras, como qualquer outro comando do shell. Portanto, é necessário fazer uma citação e escape adequados.

Veja este exemplo ao usar let

let 'foo = 2 + 1'
echo $foo
3

O uso de aspas simples aqui é absolutamente bom aqui, como não há necessidade de expansões variáveis ​​aqui, considere um caso de

bar=1
let 'foo = $bar + 1'

falharia miseravelmente, pois as $baraspas simples não se expandiriam e precisam ser citadas duas vezes como

let 'foo = '"$bar"' + 1'

Esse deve ser um dos motivos, $((..))sempre deve ser considerado o uso excessivo let. Porque dentro dele, o conteúdo não está sujeito à divisão de palavras. O exemplo anterior usando letpode ser simplesmente escrito como

(( bar=1, foo = bar + 1 ))

Lembre-se sempre de usar $((..))sem aspas simples

Embora $((..))possa ser usado com aspas duplas, não há objetivo, pois o resultado não pode conter um conteúdo que necessite de aspas duplas. Apenas certifique-se de que não esteja entre aspas simples.

printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2

Em alguns casos especiais do uso do $((..))operador dentro de uma única cadeia de caracteres entre aspas, é necessário interpolar aspas de maneira que o operador fique sem aspas ou entre aspas duplas. Por exemplo, considere um caso, quando você está tentando usar o operador dentro de uma curlinstrução para passar um contador toda vez que uma solicitação é feita, faça

curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'

Observe o uso de aspas duplas aninhadas dentro, sem as quais a cadeia literal $((reqcnt++))é passada para o requestCountercampo.

Inian
fonte
2
Charles Duffy faz um bom caso aqui para citando dupla $((...))também. É poderia ser "um pouco" paranóico e bastante improvável que tenha IFS=0, por exemplo, mas certamente não é impossível :)
PesaThe
Há também a $[[...]]sintaxe herdada, mas talvez você tenha razão em esquecê-la.
Tripleee 27/11