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//'