Ho ricevuto il seguente errore:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution e questo è lo 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 Commenti
- Cosa stai cercando di ottenere con le parentesi graffe? Cita anche le tue variabili.
- Vedi Perché il loop sulloutput di find ' è cattiva pratica?
Risposta
 ${ ... } (parentesi graffe) contrassegna diversi tipi di  espansione dei parametri , il più semplice dei quali è semplicemente espandere il valore di una variabile. Il contenuto allinterno delle parentesi graffe nel codice non è “un nome di parametro valido, o qualsiasi altra espansione, quindi la shell si lamenta. 
 Sembra che tu voglia invece la sostituzione del comando, per questo la sintassi è $( ... ) (parentesi regolare). 
 Inoltre, ls in ls $filename | sed... sembra un po  non necessario, la variabile si espande nel nome del file e ls la passa semplicemente attraverso. Potresti semplicemente utilizzare echo "$filename" | sed ... invece. 
Detto questo, puoi apportare queste modifiche direttamente nella shell:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}" oppure, utilizzando gli operatori standard:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string  Se esegui sed, tieni presente che . corrisponde a qualsiasi carattere normale espressioni, quindi sarebbe più corretto citarla con una barra rovesciata. Inoltre puoi assegnare a una sed istanza entrambi i comandi: sed -e "s/assemblyDB\.//" -e "s/\.las//". 
 E poi for filename in $(find . -type f -name "assemblyDB.*.las"); do ha tutti i problemi di  parsing ls , principalmente il fatto che spazi bianchi e caratteri jolly nei nomi dei file lo interrompono. In ksh / Bash / zsh, puoi eseguire lintero ciclo nella shell: 
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ... Commenti
Risposta
 Invece di ${} usa i backtick ` [Il pulsante sotto Esc sulla tastiera.] 
Commenti
-  Per favore don ' t utilizzare i backtick. Usa la sostituzione dei comandi. $( ... )
- Sono obsoleti, difficili da leggere, non ' n nidificano e possono sempre essere sostituito dalla sostituzione del comando tra parentesi. Inoltre sono difficili da inserire in blocchi di codice in linea sulla maggior parte dei linguaggi markdown 🙂
- Sì, è vero. Ma per quanto riguarda questa domanda dove è andata storta la mia risposta ??
- Hai suggerito di utilizzare i backtick.
-  @Jesse_b Ci ' ce nè in abbondanza dei motivi per non utilizzare i backtick, ma lincapacità di nidificarli non è uno di questi: echo `echo \`echo hello\``. Sì, richiede lescape, ma ciò significa semplicemente che ' non è così facile da nidificare come$(...), non che ' è impossibile.
Risposta
Sostituzione comando (riga 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, come già sottolineato, a (riga 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 più breve (riga 4 scomparsa, ora viene visualizzato direttamente)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done e il comando sed può essere ridotto a (riga 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done o magari estrarre la parte centrale con sed: (ancora riga 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done ora find-iterator invece di for-iterator: (dalla riga 1 alla 3, 4 scomparse)
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 i nomi dei file sono in un ordine simile o simile, potrebbe funzionare anche quanto segue:
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 inclusi, per dimostrare i file mancanti nella sequenza).
<<<, probabilmente ha anche${var/pat/repl}. Se esegui sed, potresti semplicemente assegnare entrambe le regole a unasedistanza:sed -e 's/assemblyDB\.//' -e 's/\.las//'