dårlig erstatning, der kører $ {ls … | sed …} med bash

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

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

  • @Jesse_b, ja, men hvis din shell har <<<, har den sandsynligvis også ${var/pat/repl}. Hvis du kører sed, kan du bare give begge regler til en sed instans: sed -e 's/assemblyDB\.//' -e 's/\.las//'
  • ville bare påpeg UUOE;)

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 🙂

  • Ja, det er rigtigt. Men hvad angår dette spørgsmål, hvor gik mit svar galt ??
  • Du foreslog at bruge backticks.
  • @Jesse_b Der ' er masser af grunde til ikke at bruge backticks, men manglende evne til at rede dem er ikke en af dem: 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).

    Skriv et svar

    Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *