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

17

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

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

Estou confuso sobre quais são as diferenças. Eu acho que quando o 'em volta dele significa que é uma string, então o echo literalmente mostraria a string date ao invés de exibir a data?

    
por John 01.11.2013 / 06:33

4 respostas

16

'date' expandirá apenas para a saída do comando date . 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 à maneira como o comando echo manipula vários argumentos.)

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

Em '' date '' , as aspas simples são citações mais strongs, de modo que não permitirão a expansão de variáveis ou a substituição de comandos dentro delas.

Consulte este link para mais explicações.

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

    
por 01.11.2013 / 07:00
13

Ambos

echo 'date'

e

echo "'date'"

mostrará a data. A saída deste último parece com a saída de executar date por si só.

Há uma diferença: o que está em " quotes " será enviado para echo como um único argumento. As aspas encapsulam a saída do comando inteiro como um argumento. Como echo apenas exibe seus argumentos em ordem, com espaços intermediários, ele basicamente terá a mesma aparência.

Veja 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 após Nov foram reduzidos para 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 echo recebe um único argumento e as aspas retêm o espaço.

Isso se torna muito mais importante em outros comandos além do eco. Por exemplo, imagine um comando foo que deseja dois argumentos: uma data e um endereço de e-mail.

Isso funcionará nesse cenário:

foo "'date'" [email protected]

Mas isso confundirá o script enviando 7 argumentos:

foo 'date' [email protected]
    
por 01.11.2013 / 07:49
2

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

Em ambos os casos, eles expandem para a saída de date com 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 echo no seu caso), essa expansão está sujeita a:

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

    Por exemplo, se date produzir Fri 1 Nov 14:11:15 GMT 2013\n (como costuma acontecer em uma localidade inglesa e em um fuso horário britânico continental), e $IFS atualmente contém : , isso será dividido em 3 palavras : Fri 1 Nov 14 , 11 e 15 GMT 2013 .

  2. Geração de nome de arquivo (também conhecido como globbing ) (exceto com zsh ): ou seja, cada palavra resultante da divisão acima é procurada por caracteres curinga ( * , ? , [...] embora alguns shells tenham mais) e expandido para a lista de nomes de arquivos que correspondem a esses padrões. Por exemplo, se a saída de date for ?%? 33 */*/* UVC 3432 (como geralmente é em localidades venusianas e fuso horário UVC) e $IFS for o valor padrão), isso se expandirá para todos os nomes de arquivos de 3 caracteres não ocultos em o diretório atual cujo caractere do meio é % , 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, UVC e 3432 .

É por isso que:

  1. Você deve sempre citar (com aspas duplas) as substituições de comandos, a menos que você queira que a divisão de palavras ou a geração de nome de arquivo sejam executadas na expansão
  2. Se você quiser divisão de palavras , defina $IFS para os caracteres que deseja dividir.
  3. Se você quiser divisão de palavras , mas não geração de nome de arquivo , precisará emitir um set +f para desativá-lo.

As citações simples citam tudo, fazendo com que os caracteres do backtick sejam interpretados literalmente.

Exemplo (usando -x torna mais fácil ver o 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 removem-nos, alguns truncam a saída no primeiro caractere NUL, zsh os preserva, mas observe que, de qualquer maneira, comandos externos não aceitam argumentos contendo NULs

    
por 01.11.2013 / 15:25
0

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

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

Com '' date '', você obtém uma 'data' literal, pois não há substituição de comandos 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'
    
por 01.11.2013 / 12:40