Jeg fik følgende fejl:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
og dette er scriptet:
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
- Hvad prøver du at opnå med selerne? Citér også dine variabler.
- Se Hvorfor er looping over find ' s output dårlig praksis?
Svar
${ ... }
(krøllede seler) markerer flere slags parameterudvidelse , hvor den enkleste blot udvider værdien af en variabel. Tingene inden for seler i din kode er ikke et gyldigt parameternavn eller enhver anden udvidelse, så skallen klager.
Det ser ud til, at du vil udskifte kommandoen i stedet, for det er syntaksen $( ... )
(almindelig parentes).
Også ls
i ls $filename | sed...
virker lidt unødvendigt, udvides variablen til dit filnavn, og ls
sender den bare igennem. Du kan bare bruge echo "$filename" | sed ...
i stedet.
Når det er sagt, kunne du foretage disse ændringer direkte i skallen:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
eller ved hjælp af standardoperatørerne:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
Hvis du kører sed
, vil du måske bemærke, at .
matcher ethvert tegn i almindelig udtryk, så det ville være mere korrekt at citere det med et tilbageslag. Du kan også give en sed
begge kommandoer: sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
Og derefter for filename in $(find . -type f -name "assemblyDB.*.las"); do
har alle problemerne parsing ls har, mest det faktum, at mellemrum og jokertegn i filnavne vil bryde det. I ksh / Bash / zsh kan du gøre hele sløjfen i skallen:
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
Kommentarer
Svar
I stedet for ${}
brug backticks `
[Knappen nedenfor Escape på dit tastatur.]
Kommentarer
- Don ' Brug ikke backticks. Brug kommandosubstitution.
$( ... )
- De er forældede, de er svære at læse, de
t rede, og de kan altid erstattes af parentes-kommandosubstitution. Derudover er de svære at placere i inline-kodeblokke på de fleste markdown-sprog 🙂
echo `echo \`echo hello\``
. Ja, det kræver flugt, men det betyder bare, at det ' ikke er så let at rede som $(...)
, ikke at det ' er umuligt. Svar
Kommandosubstitution (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
svarer, som allerede påpeget, 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 væk, nu 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 reduceres til (linje 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
eller måske trække den midterste del ud med sed: (stadig linje 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
find nu iterator i stedet for for iterator: (linje 1 til 3, 4 væk)
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 dine filnavne er i sådan eller en lignende rækkefø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
(inkluderet 8 og 12 for at demonstrere manglende filer i sekvensen).
<<<
, har den sandsynligvis også${var/pat/repl}
. Hvis du kører sed, kan du bare give begge regler til ensed
instans:sed -e 's/assemblyDB\.//' -e 's/\.las//'