sostituzione errata che esegue $ {ls … | sed …} con bash

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

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

  • @Jesse_b, sì, ma se la tua shell ha <<<, probabilmente ha anche ${var/pat/repl}. Se esegui sed, potresti semplicemente assegnare entrambe le regole a una sed istanza: sed -e 's/assemblyDB\.//' -e 's/\.las//'
  • Volevo solo indica UUOE;)

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).

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *