Am primit următoarea eroare:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
și acesta este scriptul:
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done
Comentarii
- Ce încerci să realizezi cu bretele? De asemenea, citați variabilele dvs.
- Consultați De ce este o practică proastă a rezultatului ' de ieșire în buclă? >
Răspuns
${ ... }
(acoladele) marchează mai multe un fel de extindere parametru , dintre care cea mai simplă este doar extinderea valorii unei variabile. Lucrurile din interiorul parantezelor din codul dvs. nu sunt „un nume de parametru valid sau orice altă extindere, astfel încât shell-ul se plânge.
Se pare că doriți înlocuirea comenzii, pentru aceasta, sintaxa este $( ... )
(paranteză regulată).
De asemenea, ls
din ls $filename | sed...
pare puțin inutilă, variabila se extinde la numele fișierului dvs. și ls
doar o trece. Puteți folosi echo "$filename" | sed ...
în schimb.
Acestea fiind spuse, puteți face aceste modificări direct în shell:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
sau, utilizând operatorii standard:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
Dacă rulați sed
, vă recomandăm să rețineți că .
se potrivește cu orice caracter din regulat expresii, deci ar fi mai corect să o citați cu o bară inversă. De asemenea, puteți da o sed
instanță ambele comenzi: sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
Și apoi for filename in $(find . -type f -name "assemblyDB.*.las"); do
are toate problemele pe care le analizează ls , mai ales faptul că spațiul alb și metacaracterele din numele fișierelor îl vor sparge. În ksh / Bash / zsh, puteți face acea buclă întreagă în shell:
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
Comentarii
Răspuns
În loc de ${}
utilizați backticks `
[Butonul de mai jos Escape de pe tastatura dvs.]
Comentarii
- Vă rugăm să nu ' nu folosiți backticks. Folosiți înlocuirea comenzii.
$( ... )
- Sunt depășite, sunt greu de citit, nu ' nu cuibăresc și pot întotdeauna să fie înlocuit cu substituirea comenzii paranteză. În plus, sunt greu de plasat în blocuri de coduri inline în majoritatea limbajelor de marcare 🙂
- Da, este corect. Dar, în ceea ce privește această întrebare, unde a greșit răspunsul meu ??
- Ați sugerat să folosiți backticks-uri.
- @Jesse_b Există o mulțime de divuri dintre motivele pentru care nu se utilizează backticks, dar incapacitatea de a le cuibări nu este una dintre ele:
echo `echo \`echo hello\``
. Da, necesită evadare, dar asta înseamnă doar că ' nu este la fel de ușor de cuibărit ca$(...)
, nu că ' este imposibil.
Răspuns
Înlocuirea comenzii (linia 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
este echivalent, așa cum sa subliniat deja, la (linia 3, nu 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
sau mai scurt (linia 4 dispărută, acum ecou direct)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done
și comanda sed poate fi redusă la (linia 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
sau poate extrage partea de mijloc cu sed: (linia încă 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
acum find-iterator în loc de for-iterator: (rândul 1 la 3, 4 dispărut)
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
Dacă numele fișierelor dvs. sunt în o astfel de ordine sau o ordine similară, ar putea funcționa și următoarele:
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 și 12 incluse, pentru a demonstra fișierele lipsă din secvență).
<<<
, probabil că are și${var/pat/repl}
. Dacă rulați sed, puteți da ambele reguli unei singuresed
instanță:sed -e 's/assemblyDB\.//' -e 's/\.las//'