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 unased
istanza:sed -e 's/assemblyDB\.//' -e 's/\.las//'