Recebi o seguinte erro:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
e este é o 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
Comentários
- O que você está tentando realizar com o aparelho? Cite também suas variáveis.
- Consulte Por que o loop sobre a saída de find ' s é uma prática ruim?
Resposta
${ ... }
(colchetes) marca vários tipos de expansão de parâmetro , a mais simples delas é apenas expandir o valor de uma variável. As coisas entre colchetes em seu código não são “um nome de parâmetro válido, ou qualquer outra expansão, então o shell reclama.
Você parece querer a substituição do comando, para isso, a sintaxe é $( ... )
(parênteses regulares).
Além disso, o ls
em ls $filename | sed...
parece um pouco desnecessário, a variável se expande para o seu nome de arquivo e ls
apenas o transmite. Você pode simplesmente usar echo "$filename" | sed ...
em vez disso.
Dito isso, você pode fazer essas modificações diretamente no shell:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
ou, usando os operadores padrão:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
Se você executar sed
, talvez queira observar que .
corresponde a qualquer caractere em expressões, então seria mais correto citá-lo com uma barra invertida. Além disso, você pode dar a uma sed
instância os dois comandos: sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
E então for filename in $(find . -type f -name "assemblyDB.*.las"); do
tem todos os problemas análise de ls tem, principalmente o fato de que espaços em branco e curingas em nomes de arquivo podem quebrá-lo. Em ksh / Bash / zsh, você pode fazer todo esse loop no shell:
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
Comentários
Resposta
Em vez de ${}
use backticks `
[O botão abaixo de Escape em seu teclado.]
Comentários
- Por favor, não ' t use crases. Use a substituição de comando.
$( ... )
- Eles estão desatualizados, são difíceis de ler, não ' t aninhados e podem sempre ser substituído por uma substituição de comando entre parênteses. Além disso, eles são difíceis de colocar em blocos de código embutidos na maioria das linguagens de markdown 🙂
- Sim, isso mesmo. Mas com relação a essa pergunta, onde minha resposta deu errado ??
- Você sugeriu usar crases.
- @Jesse_b Há ' muitos de razões para não usar crases, mas a incapacidade de aninhá-los não é uma delas:
echo `echo \`echo hello\``
. Sim, requer escape, mas isso significa apenas que ' não é tão fácil de aninhar como$(...)
, não que ' é impossível.
Resposta
Substituição de comando (linha 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
é equivalente, como já apontado, a (linha 3, não 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
ou mais curto (linha 4 sumida, agora echo diretamente)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done
e o comando sed pode ser reduzido para (linha 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
ou talvez extraia a parte do meio com sed: (ainda linha 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
agora find-iterator em vez de for-iterator: (linha 1 a 3, 4 desaparecido)
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
Se seus nomes de arquivo estiverem em tal ou uma ordem semelhante, o seguinte pode funcionar também:
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 e 12 incluídos, para demonstrar arquivos ausentes na sequência).
<<<
, provavelmente também terá${var/pat/repl}
. Se você executar o sed, poderá apenas fornecer as duas regras a umased
instância:sed -e 's/assemblyDB\.//' -e 's/\.las//'