Escribí este script:
#!/bin/bash
while [ true ]
do
currentoutput="$(lsusb)"
if [ "$currentoutput" != "$lastoutput" ]
then
echo "" date and Time >> test.log
date +%x_r >> test.log
lastoutput="$(lsusb)"
lsusb >> test.log
fi
sleep 5
done
Soy un novato tratando de aprender rápido y tengo una pregunta sobre las comillas de la variable .
Ponga una variable entre $ (), lo entiendo, pero ¿por qué se necesitan las comillas incluso en la if
declaración? ¿Es para hacer un comando anidado?
while [ true ]
produce un bucle infinito, pero tal vez no por la razón que cree que lo hace;while [ false ]
también produce un bucle infinito, porque con un solo argumento,[ ... ]
tiene éxito si ese argumento es una cadena no vacía.while true
en realidad ejecutará un comando llamadotrue
(que siempre tiene éxito).$()
. Pones un comando dentro$()
.Respuestas:
Las comillas evitan la "división de palabras". Es decir: desglosar las variables en varios elementos en los espacios en blanco (o para ser más exactos, en espacios, tabulaciones y líneas nuevas como se define en el valor de la
$IFS
variable de shell predeterminada ).Por ejemplo,
Aquí definimos la
howmany
función que simplemente nos permite saber cuántos parámetros posicionales se dan. Como puede ver, hay dos elementos que se pasan a la variable, y con las comillas, el texto en la variable se trata como una unidad.Esto es importante para el paso preciso de la información. Por ejemplo, si la variable contiene la ruta al archivo y el nombre del archivo contiene espacios en cualquier parte de la ruta, el comando que está intentando ejecutar puede fallar o dar resultados inexactos. Si estuviéramos intentando crear un archivo con la
$var
variable,touch $var
crearíamos dos archivos, perotouch "$var"
solo uno.Lo mismo va para tu
[ "$currentoutput" != "$lastoutput" ]
parte. Esta prueba particular realiza una comparación en dos cadenas. Cuando se ejecuta la prueba, el[
comando necesitaría ver 3 argumentos: una cadena de texto, el!=
operador y otra cadena de texto. Mantener comillas dobles evita la división de palabras, y el[
comando ve exactamente esos 3 argumentos. ¿Qué sucede si las variables no están entre comillas?Aquí, la división de palabras, y en su lugar
[
ve a dos cadenashello
yworld
seguido por!=
, seguidas de otras dos cadenashi world
. El punto clave es que sin comillas dobles, el contenido de las variables se entiende como unidades separadas en lugar de un elemento completo.Asignar la sustitución de comandos no requiere comillas dobles como en
donde tiene
df
guardada la salida del comandovar
. Sin embargo, es una buena costumbre siempre duplicar las variables de comillas y la sustitución de comandos a$(...)
menos que de hecho desee que la salida se trate como elementos separados.En una nota al margen, el
parte puede ser
[
es un comando que evalúa sus argumentos y[ whatever ]
siempre es verdadero independientemente de lo que haya dentro. Por el contrario,while true
usa el comandotrue
que siempre devuelve el estado de salida de éxito (y eso es exactamente lo quewhile
necesita el bucle). La diferencia es un poco más de claridad y menos pruebas realizadas. Alternativamente, también podría usar en:
lugar detrue
Las comillas dobles en
echo "" date and Time
parte probablemente podrían eliminarse. Simplemente insertan una cadena vacía y agregan espacio extra a la salida. Si eso es lo que desea, siéntase libre de mantenerlos allí, pero no hay un valor funcional particular en este caso.Esta parte probablemente podría ser reemplazada por
echo "$currentoutput" >> test.log
. No hay razón paralsusb
volver a ejecutar después de que ya se haya ejecutadocurrentoutput=$(lsusb)
. En los casos en que las nuevas líneas finales deben conservarse en la salida, se podría ver el valor de ejecutar un comando varias veces, pero en caso delsusb
que no sea necesario. Cuantos menos comandos externos llame, mejor, porque cada llamada a un comando no incorporado conlleva costos en CPU, uso de memoria y tiempo de ejecución (aunque los comandos probablemente estén precargados desde la memoria).Ver también:
fuente
bash
. Pero en la última parte no debería serecho "$currentoutput" >> test.log
mejorprintf '%s\n' "$currentoutput" >> test.log
?printf
debería preferirse por su portabilidad. Como estamos usando un script específico de bash aquí, se puede excusar su usoecho
. Pero su observación es muy correctaecho
es completamente fiable incluso cuando el depósito es conocido por ser fiesta (y el valor de losxpg_echo
yposix
las banderas se conoce); si su valor podría ser-n
o-e
, puede desaparecer en lugar de imprimirse.En
currentoutput="$(lsusb)"
lsusb no es una variable, es un comando. Lo que hace esta declaración, ejecuta ellsusb
comando y asigna su salida a lacurrentoutput
variable.La sintaxis anterior para esto era
puedes encontrarlo en muchos ejemplos y scripts
Para responder a la otra parte de su pregunta,
if [ ]
es cómoif
se define la sintaxis para bash. Ver más en https://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.htmlfuente
[ ]
realidad es eltest
comando. También puede usarif
declaraciones con otros comandos, ya que se basa en una prueba 0 o no cero de su código de salida.if grep -qe "somestring" file
que corrergrep -qe "somestring" file; if [ $? = 0 ]; then ...
, por lo que la afirmación queif [ ...
forma parte de la definición deif
sintaxis no solo es engañosa sino que conduce a malas prácticas.Lo siguiente ejecuta el comando externo
command
y devuelve su salida.Sin los corchetes / paréntesis, esto buscaría una variable en lugar de ejecutar un comando:
En cuanto a la diferencia entre
$variable
y"$variable"
, esto se vuelve relevante cuando$variable
contiene espacios. Cuando se usa"$variable"
, todo el contenido de la variable se insertará en una sola cadena, incluso si el contenido incluye espacios. Cuando se utiliza$variable
el contenido de la variable puede expandirse en una lista de argumentos de múltiples argumentos.fuente
Para ser contraria, bash recomienda que use
[[ ... ]]
over the[ ... ]
construct para evitar tener que citar variables en la prueba y, por lo tanto, los problemas asociados de división de palabras que los otros han señalado.[
se proporciona en bash para la compatibilidad POSIX con scripts destinados a ejecutarse#!/bin/sh
o aquellos que se transfieren a bash; en su mayor parte, debe evitarlo a favor[[
.p.ej
fuente
bash
no hace tal recomendación; que proporciona[[ ... ]]
lo que puede ser más conveniente y tiene algunas funciones que[ ... ]
no lo hace, pero no hay ningún problema con el uso[ ... ]
correctamente .[[
hace todo lo que[
hace y aún más, y muchas veces hace[
tropezar a las personas y luego intenta adaptar las características de[[
atrás[
para fallar y dejar los errores dispersos: es justo decir que es un recomendación de la comunidad en la medida en que las guías de estilo bash más relevantes aconsejen nunca usar[
.