¿Cuál es la diferencia entre echo `date`, echo“ `date`” y echo `` date` '?

23

¿Cuál es la diferencia entre estos tres comandos?

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

Estoy confundido sobre cuáles son las diferencias en realidad. Creo que cuando el 'está alrededor, significa que es una cadena, por lo tanto, echo literalmente generaría la cadena en datelugar de mostrar la fecha.

John
fuente

Respuestas:

19

`date` simplemente se expandirá a la salida del datecomando. Sin embargo, elimina los caracteres de espacio extra en los lugares donde hay más de un carácter de espacio consecutivo en la salida. (Esto se debe a que la sustitución del comando está sujeta a la división de palabras y a la forma en que el echocomando maneja múltiples argumentos).

En "` date` " , las comillas dobles son comillas débiles, por lo que expandirán las variables (intente" $ PWD ") y realice la sustitución de comandos. El resultado de la expansión se pasa como un argumento único al echocomando, con los espacios consecutivos incluidos: es decir, no se realiza la división de palabras .

En '' fecha`` , las comillas simples son comillas más fuertes, por lo que no permitirán la expansión de variables o la sustitución de comandos dentro de ellas.

Consulte este enlace para obtener más explicaciones.

Editó el primer punto como lo señaló correctamente Michael Suelmann en el comentario a continuación .

Chirag Bhatia - chirag64
fuente
1
¿Cómo se llama exactamente el `carácter que rodea la fecha? Si lo entiendo correctamente, ¿los metacaracteres no funcionarán entre comillas simples?
Juan
Si lo entiendo correctamente, ¿los metacaracteres no funcionarán entre comillas simples?
Juan
8
El `a menudo se denomina" backtick "en ese escenario y en varios documentos / libros de Unix. En realidad, no se usa como acento grave Unicode cuando está solo de esa manera, a pesar de que ese es el nombre del símbolo. Y tiene razón en que no se producirá una expansión de metacaracteres / expresiones si lo rodea con comillas simples.
Jim Stewart el
Su primera declaración es incorrecta, ya que la salida puede ser ligeramente diferente según la fecha o la configuración regional. Solo el segundo comando generará lo mismo que el datecomando simple .
jlliagre
1
@BonsiScott El espacio extra entre "Nov" y "1" también se elimina en HTML;)
Izkata
16

Ambos

echo `date`

y

echo "`date`"

mostrará la fecha. El resultado de este último se parece al resultado de ejecutarse datepor sí mismo.

Sin embargo, hay una diferencia: el que está entre "comillas "se enviará echocomo un argumento único. Las comillas encapsulan la salida de todo el comando como un argumento. Como echosolo imprime sus argumentos en orden, con espacios en el medio, básicamente se verá igual.

Aquí hay un ejemplo de la sutil diferencia:

echo `date`

produce:

Fri Nov 1 01:48:45 EST 2013

pero:

echo "`date`"

produce:

Fri Nov  1 01:48:49 EST 2013

Tenga en cuenta que los dos espacios posteriores Novse redujeron a uno sin las comillas. Esto se debe a que el shell analiza cada elemento separado por espacios y envía el resultado a echo como 6 argumentos. Cuando lo cita, echo recibe un solo argumento y las citas retienen el espacio.

Esto se vuelve mucho más importante en comandos que no sean echo. Por ejemplo, imagine un comando fooque quiere dos argumentos: una fecha y una dirección de correo electrónico.

Esto funcionará en ese escenario:

foo "`date`" joeuser@example.com

Pero esto confundirá el script enviándole 7 argumentos:

foo `date` joeuser@example.com
Jim Stewart
fuente
3
Eres contradictorio en tu primera oración. La primera y segunda forma no siempre generarán lo mismo que demuestre más adelante.
jlliagre el
Gracias. He cambiado la redacción para que quede más claro.
Jim Stewart el
3

En los shells POSIX, `date`es la antigua forma de sustitución de comandos. La sintaxis moderna es $(date).

En ambos casos, se expanden a la salida datecon los caracteres de línea nueva eliminados (siempre que la salida no contenga caracteres NUL).

Sin embargo, cuando no está entre comillas dobles y en contextos de lista (por ejemplo, en argumentos a comandos simples como echoen su caso), esa expansión está sujeta a:

  1. División de palabras : es decir, el "resultado de datecon los caracteres de línea nueva eliminados" se divide de acuerdo con el valor actual de la $IFSvariable (que por defecto contiene espacio, tabulación y línea nueva (y NUL con zsh)) en varias palabras .

    Por ejemplo, si datelas salidas Fri 1 Nov 14:11:15 GMT 2013\n(como ocurre a menudo en un local Inglés y en una zona horaria británica continental), y $IFSactualmente contiene :, que se dividirá en 3 palabras : Fri 1 Nov 14, 11y 15 GMT 2013.

  2. Generar nombres de archivos (también conocido como comodines ) (excepto con zsh): es decir, cada palabra que resulta de la división anterior se buscó caracteres comodín ( *, ?, [...]aunque algunos tienen cáscaras más), y ampliado a la lista de nombres de archivos que coinciden con los patrones. Por ejemplo, si la salida datees ?%? 33 */*/* UVC 3432(como es a menudo en lugares de Venus y UVC zona horaria), y $IFSes el valor predeterminado), a continuación, que se expande a todos los no-oculto 3 nombres de archivo de caracteres en el directorio actual cuyo personaje central es %, 33, todos los archivos no ocultos en todos los subdirectorios no ocultos de todos los subdirectorios no ocultos del directorio actual, UVCy 3432.

Es por eso que:

  1. Siempre debe citar (con comillas dobles) las sustituciones de comandos a menos que desee que la palabra se divida o que la generación del nombre de archivo se realice al expandirse
  2. Si desea dividir palabras , debe establecer $IFSlos caracteres en los que desea dividir.
  3. Si desea dividir palabras pero no generar nombres de archivos , debe emitir un set +fpara deshabilitarlo.

Las comillas simples citan todo, por lo que los caracteres de retroceso se toman literalmente.

Ejemplo (el uso -xfacilita ver lo que está sucediendo):

$ 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

Si la salida contiene caracteres NUL, entonces el comportamiento varía de un shell a otro: algunos los eliminan, otros truncan la salida en el primer carácter NUL, los zshconserva, pero tenga en cuenta que de todos modos los comandos externos no pueden tomar argumentos que contengan NUL

Stéphane Chazelas
fuente
No existe tal cosa como un "shell POSIX" real. Existen shells que pueden ajustarse a los diversos estándares POSIX relevantes al usar un subconjunto limitado de su funcionalidad.
fpmurphy
0

Con `fecha` se obtiene la salida de la fecha dividida en varias palabras, porque la división de palabras se realiza después de la sustitución del comando.

Con "` date` "obtienes el resultado de date como una palabra / parámetro ya que hay sustitución de comandos entre comillas dobles, pero el resultado no se analiza más. Lo mismo es válido con una expansión variable como "$ i" en mi ejemplo a continuación.

Con '' fecha '' obtienes una 'fecha' literal ya que no hay sustitución de comando entre comillas simples.

Quizás las diferencias de las 3 formas serán más visibles de esta manera:

> 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
fuente