Qual é a diferença entre aspas "...", '...', $ '...' e $ "..."?

49

Às vezes eu vejo scripts usam todas estas diferentes formas de citar algum texto: "...", '...', $'...', e $"...". Por que existem tantos tipos diferentes de cotação em uso?

Eles se comportam de maneira diferente ou afetam o que eu posso fazer dentro deles?

Michael Homer
fonte
1
Possível duplicado entre sites. Esta resposta fornece um resumo (ou links para) a semântica de todos os diferentes tipos de citações.
chepner 26/02

Respostas:

66

Tudo isso significa algo diferente, e você pode escrever coisas diferentes dentro deles (ou as mesmas coisas, com significado diferente). Diferentes tipos de citação interpretam diferentes seqüências de escape dentro deles ( \something) ou permitem ou não permitem interpolações variáveis ​​( $something) e outros tipos de expansão dentro deles.

Em resumo:

  • '...' é inteiramente literal.
  • "..." permite variáveis ​​e caracteres de aspas incorporados.
  • $'...'executa escapes de caracteres como \n, mas não expande variáveis.
  • $"..." é para traduções de idiomas humanos no Bash e no ksh.

'Aspas simples'

Tudo o que você escreve entre aspas simples é tratado literalmente e não é processado. Barras invertidas e cifrões não têm significado especial lá. Isso significa que você não pode escapar da barra invertida de um caractere (incluindo outras aspas simples!), Interpolar uma variável ou usar qualquer outro recurso de shell.

Todos esses exemplos resultam literalmente no que está escrito entre as aspas:

'hello world'                     => hello world
'/pkg/bin:$PATH'                  => /pkg/bin:$PATH
'hello\nworld'                    => hello\nworld
'`echo abc`'                      => `echo abc`
'I\'dn\'t've'                     => I\dn'tve

A última é complicada - há duas cadeias de citação simples executadas em conjunto com algum texto não citado. O primeiro contém I\. O texto não citado dn\'tcontém uma única citação que é escapada no nível do shell , portanto, não inicia uma string entre aspas e é incluída como um caractere literal (assim, dn't). A string final citada é apenas ve. Todos eles são reunidos em uma única palavra da maneira usual em que o shell funciona.

Um idioma bastante comum para combinar texto literal e variáveis ​​é executá-los juntos assim:

'let x="'$PATH\"

vai resultar em

let x="/usr/bin:/bin"

como uma única palavra (é melhor citar duas vezes $PATHtambém, apenas por maiúsculas e minúsculas - espaços ou caracteres brilhantes no valor da variável podem ser processados ​​de outra forma - mas por uma questão de exemplo legível, não o tenho).


"Aspas duplas"

Dentro de aspas duplas, dois tipos de expansão são processados ​​e você pode usar uma barra invertida para escapar de caracteres para impedir que expansões ou escapes sejam processadas.

Existem duas categorias de expansão que ocorrem entre aspas duplas:

Dentro das aspas, uma barra invertida pode inibir essas expansões colocando-a antes do $or `. Ele também pode escapar de uma citação dupla de fechamento, para \"incluir apenas "na sua string ou em outra barra invertida. Qualquer outra barra invertida é preservada literalmente - não há escapatória para produzir outros caracteres e não é removida.

Alguns desses exemplos agem de maneira diferente de antes e outros não:

"hello world"                     => hello world
"/pkg/bin:$PATH"                  => /pkg/bin:/bin:/usr/bin
"hello\nworld"                    => hello\nworld
"hello\\nworld"                   => hello\nworld
"`echo abc`"                      => abc
"I\'dn\'t've"                     => I\'dn\'t've
"I'dn't've"                       => I'dn't've
"I\"dn\"t've"                     => I"dn"t've

$ 'Cotação ANSI-C'

Esse tipo de citação permite que escapes de barra invertida no estilo C sejam processados, mas não variáveis ​​ou substituições incorporadas. É o único tipo de citação que suporta escapes de caracteres .

Esta é uma extensão do ksh, agora suportada no Bash, zsh e em alguns outros shells. Não é ainda parte do padrão POSIX e scripts para maximamente-portáteis não podem usá-lo, mas um script Bash ou ksh é livre para.

Todos esses escapes podem ser usados com os seus significados C: \a, \b, \f, \n, \r, \t, \v, e os escapes literais \\, \', \", e \?. Eles também suportam as extensões \e(caractere de escape) e no Bash e ksh \cx(o que seria inserido por Ctrl-x , por exemplo, \cMé retorno de carro). Os reservatórios têm uma série de extensões menores próprias.

Ele também permite quatro tipos de escape de caracteres genéricos:

  • \nnn, um único byte com valor octal nnn
  • \xHH, um único byte com valor hexadecimal HH
  • \uHHHH, o ponto de código Unicode cujo índice hexadecimal é HHHH
  • \UHHHHHHHH, o ponto de código Unicode cujo índice hexadecimal é HHHHHHHH

Todos esses dígitos são opcionais após o primeiro.

$e `não têm significado e são preservadas literalmente, então você não pode incluir uma variável lá.

$'hello world'                    => hello world
$'/pkg/bin:$PATH'                 => /pkg/bin:$PATH
$'hello\nworld'                   => hello
                                     world
$'`echo abc`'                     => `echo abc`
$'I\'dn\'t\'ve'                   => I'dn't've
$'\U1f574\u263A'                  => 🕴☺

A maioria desses escapes você pode simular usando o printfcomando , embora POSIX requer apenas \\, \a, \b, \f, \n, \r, \t, \v, e \nnnpara trabalhar lá. Você pode usar substituição de comando para incorporar um printfdentro de aspas duplas se necessário: "Path:$(printf '\t')$PATH".


$ "Tradução local"

Essa é uma extensão específica do ksh e do Bash para localizar seqüências de texto em idioma natural e procura a parte dentro das aspas em um catálogo de mensagens. Ele executa todas as expansões de aspas duplas primeiro. Se a sequência não for encontrada no banco de dados de tradução, ela será usada como sua própria tradução. A suposição interna é que as strings estão em inglês.

Você provavelmente não deseja usar este, mas se o vir, geralmente poderá tratá-lo como aspas duplas regulares.


Um ponto de observação é que não há nenhum tipo de citação que permita a expansão de parâmetros incorporados e os caracteres incorporados escapam. Na maioria dos casos em que você deseja isso, seria melhor (mais seguro) usar printf:

printf 'New path: \e[1m%s\e[0m' "/pkg/bin:$PATH:"

Isso separa claramente quais partes estão sujeitas a escape de caracteres e quais são os valores dos dados.

Outra é que todos esses estilos de citação criam uma única "palavra" no shell, a menos que $@ uma expansão de matriz ${x[@]}seja usada entre aspas duplas. Os dois formulários de aspas simples são sempre uma palavra e nunca se expandem mais.

Michael Homer
fonte
$"..."também é do ksh93, adicionado ao bash no 2.0.
Stéphane Chazelas 27/02
Não há \cXdentro zsh. É \CXou está \C-Xlá ( \cjá tem um significado especial echo)
Stéphane Chazelas 27/02
'let x="'$PATH\"está errado em contextos lista em que não sejam conchas zshcomo $PATHnão é citado (assim estaria sujeito a divisão + glob que você não gostaria que aqui).
Stéphane Chazelas 27/02
Você pode esclarecer que está falando de conchas do tipo Korn, o processamento de cotações é diferente em csh, rc, fish ...
Stéphane Chazelas -
@ StéphaneChazelas Defina "contexto da lista".
Isaac