Recibí el siguiente error:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
y este es el script:
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done
Comentarios
- ¿Qué está tratando de lograr con los frenos? También cite sus variables.
- Consulte ¿Por qué el bucle sobre el resultado de find ' es una mala práctica?
Respuesta
${ ... }
(llaves) marca varias tipos de expansión de parámetros , la más simple de las cuales es simplemente expandir el valor de una variable. El contenido entre llaves en su código no es un nombre de parámetro válido, o cualquier otra expansión, por lo que el shell se queja.
Parece que desea la sustitución de comandos en su lugar, para eso, la sintaxis es $( ... )
(paréntesis regular).
Además, el ls
en ls $filename | sed...
parece un poco innecesaria, la variable se expande a su nombre de archivo, y ls
simplemente la pasa. Puede usar echo "$filename" | sed ...
en su lugar.
Dicho esto, podrías hacer esas modificaciones directamente en el shell:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
o, usando los operadores estándar:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
Si ejecuta sed
, es posible que desee tener en cuenta que .
coincide con cualquier carácter en expresiones, por lo que sería más correcto citarlo con una barra invertida. También puede dar una sed
instancia ambos comandos: sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
Y luego for filename in $(find . -type f -name "assemblyDB.*.las"); do
tiene todos los problemas que tiene al analizar ls , principalmente el hecho de que los espacios en blanco y los comodines en los nombres de archivo lo romperán. En ksh / Bash / zsh, podría hacer todo ese ciclo en el shell:
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
Comentarios
Responder
En lugar de ${}
use comillas inversas `
[El botón debajo de Escape en su teclado.]
Comentarios
- Por favor, no ' t use comillas invertidas. Utilice la sustitución de comandos.
$( ... )
- Están desactualizados, son difíciles de leer, no ' t anidan y pueden siempre ser reemplazado por la sustitución de comandos entre paréntesis. Además, son difíciles de colocar en bloques de código en línea en la mayoría de los lenguajes de rebajas 🙂
- Sí, es cierto. Pero en lo que respecta a esta pregunta, ¿dónde salió mal mi respuesta?
- Sugirió usar comillas invertidas.
- @Jesse_b Hay ' muchos de las razones para no usar comillas inversas, pero la incapacidad de anidarlas no es una de ellas:
echo `echo \`echo hello\``
. Sí, requiere escapar, pero eso solo significa que ' no es tan fácil de anidar como$(...)
, no es que ' es imposible.
Responder
Sustitución de comandos (línea 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=$(ls $filename | sed "s/assemblyDB.//" | sed "s/.las//") echo $no done
es equivalente, como ya se señaló, a (línea 3, no ls
)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=$(echo $filename | sed "s/assemblyDB.//" | sed "s/.las//") echo $no done
o más corto (línea 4 desaparecida, ahora echo directamente)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done
y el comando sed se puede reducir a (línea 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
o tal vez extraiga la parte del medio con sed: (línea fija 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
ahora find-iterator en lugar de for-iterator: (línea 1 a 3, 4 desaparecida)
find . -type f -name "assemblyDB.*.las" -printf "%f\n" -exec sh -c " echo {} | sed -r "s/.*assemblyDB.(.*).las/\1/"" ";" assemblyDB.11.las 11 assemblyDB.9.las 9 assemblyDB.10.las 10
Si sus nombres de archivo están en tal o un orden similar, lo siguiente también podría funcionar:
for i in {8..12} ; do ls assemblyDB.$i.las && echo $i ; done 2>/dev/null assemblyDB.9.las 9 assemblyDB.10.las 10 assemblyDB.11.las 11
(8 y 12 incluidos, para demostrar los archivos que faltan en la secuencia).
<<<
, probablemente también tenga${var/pat/repl}
. Si ejecuta sed, simplemente podría asignar ambas reglas a unased
instancia:sed -e 's/assemblyDB\.//' -e 's/\.las//'