Jeg fikk følgende feil:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
og dette er skriptet:
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done
Kommentarer
- Hva prøver du å oppnå med selene? Sitat også på variablene dine.
- Se Hvorfor er sløyfing over finne ' s utgang dårlig praksis?
Svar
${ ... }
(krøllete bukseseler) markerer flere slags parameterutvidelse , den enkleste er bare å utvide verdien til en variabel. Tingene i seler i koden din er ikke et gyldig parameternavn eller annen utvidelse, så skallet klager.
Du ser ut til å ønske å bytte kommando i stedet, for det er syntaksen $( ... )
(vanlig parentes).
Også ls
i ls $filename | sed...
virker litt unødvendig utvides variabelen til filnavnet ditt, og ls
sender den bare gjennom. Du kan bare bruke echo "$filename" | sed ...
i stedet.
Når det er sagt, kan du gjøre disse endringene direkte i skallet:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
eller ved å bruke standardoperatørene:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
Hvis du kjører sed
, kan det være lurt å merke seg at .
samsvarer med hvilket som helst tegn i vanlig uttrykk, så det ville være riktigere å sitere det med tilbakeslag. Du kan også gi en sed
begge kommandoene: sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
Og så for filename in $(find . -type f -name "assemblyDB.*.las"); do
har alle problemene parsing ls har, mest det faktum at hvite mellomrom og jokertegn i filnavn vil bryte det. I ksh / Bash / zsh kan du gjøre hele sløyfen i skallet:
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
Kommentarer
Svar
I stedet for ${}
bruk backticks `
[Knappen nedenfor Escape på tastaturet ditt.]
Kommentarer
- Vennligst ikke ' Ikke bruk backticks. Bruk kommandosubstitusjon.
$( ... )
- De er foreldede, de er vanskelige å lese, de ' t hekker, og de kan alltid erstattes av parentes-kommandosubstitusjon. I tillegg er de vanskelig å plassere i innebygde kodeblokker på de fleste markdown-språk 🙂
- Ja, det stemmer. Men når det gjelder dette spørsmålet, hvor gikk svaret mitt galt ??
- Du foreslo å bruke backticks.
- @Jesse_b ' det er nok av grunner til ikke å bruke backticks, men manglende evne til å rede dem er ikke en av dem:
echo `echo \`echo hello\``
. Ja, det krever å rømme, men det betyr bare at det ' ikke er så lett å hekke som$(...)
, ikke at det ' er umulig.
Svar
Kommandosubstitusjon (linje 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
tilsvarer, som allerede påpekt, til (linje 3, ingen 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
eller kortere (linje 4 borte, nå ekko direkte)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done
og kommandoen sed kan reduseres til (linje 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
eller kanskje trekke ut den midtre delen med sed: (still linje 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
finn nå iterator i stedet for for iterator: (linje 1 til 3, 4 borte)
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
Hvis filnavnene dine er i slik eller lignende rekkefølge, kan følgende også fungere:
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
(inkludert 8 og 12, for å demonstrere manglende filer i sekvensen).
<<<
, har det sannsynligvis også${var/pat/repl}
. Hvis du kjører sed, kan du bare gi begge reglene til ensed
forekomst:sed -e 's/assemblyDB\.//' -e 's/\.las//'