Qual é a diferença entre echo `date`, echo“ date ”e echo 'date'?

23

Qual é a diferença entre esses três comandos?

echo `date`
echo "`date`"
echo '`date`'

Estou confuso sobre quais são realmente as diferenças. Eu acho que quando o 'está por perto significa que é uma string, portanto, o eco literalmente produziria a string em datevez de exibir a data?

John
fonte

Respostas:

19

`date` será expandido apenas para a saída do datecomando. No entanto, ele remove caracteres de espaço extra em locais onde há mais de um caractere de espaço consecutivo na saída. (Isso ocorre porque a substituição do comando está sujeita à divisão de palavras e devido à maneira como o echocomando lida com vários argumentos.)

Em "` date` " , as aspas duplas são aspas fracas; portanto, elas expandem variáveis ​​(tente" $ PWD ") e executam a substituição de comandos. O resultado da expansão é passado como um único argumento para o echocomando, com espaços consecutivos incluídos: ou seja, a divisão de palavras não é executada.

Em `` data '' , as aspas simples são aspas mais fortes, portanto, não permitirão a expansão de variáveis ​​ou a substituição de comandos dentro delas.

Consulte este link para obter mais explicações.

Editou o primeiro ponto como apontado corretamente por Michael Suelmann no comentário abaixo .

Chirag Bhatia - chirag64
fonte
1
O que exatamente é chamado o caractere que está ao redor da data? Se estou entendendo corretamente, os meta caracteres não funcionarão entre aspas simples?
John
Se estou entendendo corretamente, os meta caracteres não funcionarão entre aspas simples?
John
8
O `é frequentemente chamado de" backtick "nesse cenário e em vários livros / documentação do Unix. Na verdade, ele não está sendo usado como um sotaque grave Unicode quando é por si só assim, mesmo que esse seja o nome do símbolo. E você está certo de que nenhuma expansão de metacaracteres / expressões ocorrerá se você o envolver entre aspas simples.
perfil completo de Jim Stewart
Sua primeira instrução está incorreta, pois a saída pode ser um pouco diferente dependendo da data ou localidade. Somente o segundo comando produzirá a mesma coisa que o datecomando bare .
Jlliagre #
1
@BonsiScott O espaço extra entre "Novembro" e "1" é removido em HTML como bem;)
Izkata
16

Ambos

echo `date`

e

echo "`date`"

exibirá a data. A saída deste último parece com a saída sendo executada datepor si só.

Porém, há uma diferença: a pessoa entre "aspas "será enviada para echocomo um único argumento. As aspas encapsulam a saída de todo o comando como um argumento. Como echoapenas imprime seus argumentos em ordem, com espaços no meio, basicamente parecerá o mesmo.

Aqui está um exemplo da diferença sutil:

echo `date`

produz:

Fri Nov 1 01:48:45 EST 2013

mas:

echo "`date`"

produz:

Fri Nov  1 01:48:49 EST 2013

Observe que os dois espaços seguintes Novforam reduzidos a um sem as aspas. Isso ocorre porque o shell está analisando cada elemento separado por espaço e enviando o resultado para ecoar como 6 argumentos. Quando você cita, o eco recebe um único argumento e as aspas retêm o espaço.

Isso se torna muito mais importante em comandos que não sejam eco. Por exemplo, imagine um comando fooque queira dois argumentos: uma data e um endereço de email.

Isso funcionará nesse cenário:

foo "`date`" joeuser@example.com

Mas isso confundirá o script enviando-o 7 argumentos:

foo `date` joeuser@example.com
Jim Stewart
fonte
3
Você é auto-contraditório na sua primeira frase. O primeiro e o segundo formulário nem sempre exibem a mesma coisa que você demonstra posteriormente.
Jlliagre #
Obrigado. Eu mudei o texto para deixar mais claro.
Jim Stewart
3

Nos shells POSIX, `date`é a forma antiga de substituição de comando. A sintaxe moderna é $(date).

Nos dois casos, eles se expandem para a saída datecom os caracteres de nova linha à direita removidos (desde que a saída não contenha caracteres NUL).

No entanto, quando não estiver entre aspas duplas e em contextos de lista (por exemplo, em argumentos para comandos simples, como echono seu caso), essa expansão estará sujeita a:

  1. Divisão de palavras : ou seja, a "saída de datecom os caracteres de nova linha à direita removidos" é dividida de acordo com o valor atual da $IFSvariável (por padrão, contendo espaço, tabulação e nova linha (e NUL com zsh)) em várias palavras .

    Por exemplo, se dateas saídas Fri 1 Nov 14:11:15 GMT 2013\n(como costuma acontecer em um local Inglês e em um fuso horário britânico continente), e $IFSatualmente contém :, que será dividido em 3 palavras : Fri 1 Nov 14, 11e 15 GMT 2013.

  2. Geração de nome de arquivo (aka englobamento ) (exceto com zsh): isto é, cada palavra resultante da divisão acima é procurado caracteres curinga ( *, ?, [...]embora algumas conchas têm mais), e expandiu-se para a lista de nomes de arquivos que correspondem a esses padrões. Por exemplo, se a saída dateé ?%? 33 */*/* UVC 3432(como muitas vezes é em locais venusianos e fuso horário UVC), e $IFSé o valor padrão), em seguida, que se expande para todos os não-escondida 3 nomes de personagens no diretório atual cujo personagem central é %, 33, todos os arquivos não ocultos em todos os subdiretórios não ocultos de todos os subdiretórios não ocultos do diretório atual UVCe 3432.

É por isso que:

  1. Você deve sempre citar (com aspas duplas) substituições de comando, a menos que queira que a divisão de palavras ou a geração de nome de arquivo sejam executadas após sua expansão
  2. Se você deseja dividir as palavras , defina $IFSos caracteres nos quais deseja dividir.
  3. Se você deseja dividir as palavras, mas não gerar o nome do arquivo , é necessário emitir a set +fpara desativá-lo.

As aspas simples citam tudo, fazendo com que os caracteres do backtick sejam interpretados literalmente.

Exemplo (o uso -xfacilita a visualização do que está acontecendo):

$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

Se a saída contiver caracteres NUL, o comportamento varia de shell para shell: alguns os removem, outros truncam a saída no primeiro caractere NUL, zshpreservam-nos, mas observe que de qualquer maneira os comandos externos não podem aceitar argumentos que contenham NULs

Stéphane Chazelas
fonte
Não existe um "shell POSIX" real. Existem shells que podem estar em conformidade com os vários padrões POSIX relevantes usando um subconjunto limitado de sua funcionalidade.
fpmurphy
0

Com `date ', você obtém a saída da data dividida em várias palavras, porque a divisão da palavra é feita após a substituição do comando.

Com "` date` ", você obtém a saída da data como uma palavra / parâmetro, pois há substituição de comando entre aspas duplas, mas a saída não é mais analisada. O mesmo é válido com expansão variável como "$ i" no meu exemplo abaixo.

Com '`date' ', você obtém uma` date' literal, pois não há substituição de comando entre aspas simples.

Talvez as diferenças das três formas sejam mais visíveis desta maneira:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`
Michael Suelmann
fonte