puedo escribir
VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"
El resultado final para mí parece casi igual. ¿Por qué debería escribir uno u otro? ¿Alguno de estos no es portátil / POSIX?
puedo escribir
VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"
El resultado final para mí parece casi igual. ¿Por qué debería escribir uno u otro? ¿Alguno de estos no es portátil / POSIX?
Respuestas:
VAR=$VAR1
es una versión simplificada de VAR=${VAR1}
. Hay cosas que el segundo puede hacer que el primero no puede, por ejemplo, hacer referencia a un índice de matriz (no portátil) o eliminar una subcadena (POSIX-portátil). Consulte la sección Más sobre variables de la Guía Bash para principiantes y Expansión de parámetros en la especificación POSIX.
Usar comillas alrededor de una variable como en rm -- "$VAR1"
o rm -- "${VAR}"
es una buena idea. Esto hace que el contenido de la variable sea una unidad atómica. Si el valor de la variable contiene espacios en blanco (bueno, caracteres en la $IFS
variable especial, espacios en blanco por defecto) o caracteres globales y no lo cita, entonces cada palabra se considera para la generación de nombre de archivo (globalización) cuya expansión genera tantos argumentos para lo que sea que estas haciendo.
$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'
$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename
Sobre portabilidad: de acuerdo con POSIX.1-2008 sección 2.6.2 , las llaves son opcionales.
var1=$var
expansión da un error?
export VAR=$VAR1
. En cuanto a las llaves, son opcionales (verifique el cuarto párrafo de la sección que citó; este es el caso en todos los shells pre-POSIX y POSIX).
${VAR}
y $VAR
son exactamente equivalentes Para una expansión de variable simple, la única razón para usar ${VAR}
es cuando el análisis de otra manera tomaría demasiados caracteres en el nombre de la variable, como en ${VAR1}_$VAR2
(que sin llaves sería equivalente a ${VAR1_}$VAR2
). Expansiones más adornados ( ${VAR:=default}
, ${VAR#prefix}
, ...) requieren apoyos.
En una asignación variable, la división del campo (es decir, la división en el espacio en blanco en el valor) y la expansión del nombre de ruta (es decir, globbing) se desactivan, por lo que VAR=$VAR1
es exactamente equivalente a VAR="$VAR1"
, en todos los shells POSIX y en todos los sh anteriores a POSIX de los que he oído hablar. . (Ref. POSIX: comandos simples ). Por la misma razón, se VAR=*
establece de manera confiable VAR
en la cadena literal *
; por supuesto, VAR=a b
establece VAR
que a
ya que b
es una palabra separada en primer lugar. En términos generales, las comillas dobles son innecesarias cuando la sintaxis de shell espera una sola palabra, por ejemplo encase … in
(pero no en el patrón), pero incluso allí debe tener cuidado: por ejemplo, POSIX especifica quelos objetivos de redirección ( >$filename
) no requieren comillas en los scripts, pero algunos shells, incluido bash, requieren comillas dobles incluso en scripts. Ver ¿ Cuándo es necesaria la doble cita? para un análisis más completo
Necesita las comillas dobles en otros casos, en particular en export VAR="${VAR1}"
(que se puede escribir de manera equivalente export "VAR=${VAR1}"
) en muchos shells (POSIX deja este caso abierto). La similitud de este caso con asignaciones simples y la naturaleza dispersa de la lista de casos en los que no necesita comillas dobles, es por eso que recomiendo usar comillas dobles a menos que desee dividir y englobar.
IFS
carácter porque quiero tener el hábito. La única excepción es que no cito el valor cuando hago una asignación variable (a menos que sea necesario, como cuando el valor contiene un espacio). Esto hace que el resaltado de sintaxis del editor sea más útil cuando hay sustituciones de comandos como FOO=$(BAR=$(BAZ=blah; printf %s "${BAZ}"); printf %s "${BAR}")
. En lugar de colorear todo el color de "cadena", obtengo resaltado de sintaxis del código anidado. Por eso también evito los backticks.
>$file
está bien en los scripts POSIX, no está en bash incluso cuando no es interactivo (a menos que se cumpla con POSIX $POSIXLY_CORRECT
o --posix
...).
VAR=$VAR1
, a veces me ha sorprendido local VAR=$VAR1
que recuerdo haber trabajado de manera diferente en algunos aspectos, al menos en algunos shells. Pero atm, no puedo reproducir la divergencia.
local VAR=$VAR1
es como export VAR=$VAR1
, depende del shell.
Tenga en cuenta que la comilla doble se usa para la expansión variable, y la comilla simple se usa para las comillas fuertes, es decir, sin expansión.
this='foo'
that='bar'
these="$this"
those='$that'
for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that
Puede valer la pena mencionar que debe usar la cita siempre que sea posible por varias razones, entre las cuales se considera la mejor práctica y la legibilidad. También porque Bash es peculiar a veces y a menudo por formas aparentemente ilógicas o irrazonables / inesperadas, y la cita cambia las expectativas implícitas a explícitas, lo que reduce esa superficie de error (o potencial para ello).
Y aunque es completamente legal no cotizar, y funcionará en la mayoría de los casos, esa funcionalidad se proporciona por conveniencia y probablemente sea menos portátil. La práctica totalmente formal garantizada para reflejar la intención y la expectativa es citar.
Ahora considere también que la construcción "${somevar}"
se usa para operaciones de sustitución. Varios casos de uso, como reemplazo y matrices.
thisfile='foobar.txt.bak'
foo="${thisfile%.*}" # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}" # removes longest matching
for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar
foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}" #single occurrence
bar="${foobar//least/most}" #global occurrence (all)
for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful
mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls
alpha=($(ls temp/*))
echo "$alpha" # temp/foo.txt
echo "${alpha}" # temp/foo.txt
echo "${alpha[@]}" # temp/bar.txt temp/foobar.txt temp/foo.txt
echo "${#alpha}" # 12 # length of first element (implicit index [0])
echo "${#alpha[@]}" # 3 # number of elements
echo "${alpha[1]}" # temp/foobar.txt # second element
echo "${#alpha[1])" # 15 # length of second element
for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt
Todo esto apenas está rascando la superficie de la "${var}"
construcción de sustitución. La referencia definitiva para el script de shell Bash es la referencia en línea libre, TLDP The Linux Documentation Projecthttps://www.tldp.org/LDP/abs/html/parameter-substitution.html
ls -la
lrwxrwxrwx. 1 root root 31 Nov 17 13:13 prodhostname
lrwxrwxrwx. 1 root root 33 Nov 17 13:13 testhostname
lrwxrwxrwx. 1 root root 32 Nov 17 13:13 justname
termina entonces:
env=$1
if [ ! -f /dirname/${env}hostname ]
Vale la pena mencionar como un ejemplo más claro del uso de curvas