dålig ersättning som kör $ {ls … | sed …} med bash

Jag fick följande fel:

./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution 

och detta är 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

Svar

${ ... } (lockiga hakparenteser) markerar flera sorter av parameterutvidgning , varav det enklaste är att bara utvidga värdet på en variabel. Grejerna inom hängslen i din kod är inte ett giltigt parameternamn eller någon annan expansion, så skalet klagar.

Du verkar vilja byta kommando istället, för det är syntaxen $( ... ) (vanlig parentes).

Dessutom verkar ls i ls $filename | sed... onödigt expanderar variabeln till ditt filnamn och ls skickar bara igenom den. Du kan bara använda echo "$filename" | sed ... istället.

Med detta sagt kan du göra dessa ändringar direkt i skalet:

no="${filename/assemblyDB.}" # remove first match no="${no/.las}" 

eller med standardoperatörerna:

no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string 

Om du kör sed kanske du vill notera att . matchar alla tecken i vanlig uttryck, så det skulle vara mer korrekt att citera det med en backslash. Du kan också ge en sed instans båda kommandona: sed -e "s/assemblyDB\.//" -e "s/\.las//".

Och sedan for filename in $(find . -type f -name "assemblyDB.*.las"); do har alla problem parsing ls har, mestadels det faktum att blanksteg och jokertecken i filnamn kommer att bryta det. I ksh / Bash / zsh kan du göra hela slingan i skalet:

shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ... 

Kommentarer

  • @Jesse_b, ja, men om ditt skal har <<<, har det troligen ${var/pat/repl}. Om du kör sed kan du bara ge båda reglerna till en sed instans: sed -e 's/assemblyDB\.//' -e 's/\.las//'
  • Ville bara påpeka UUOE;)

Svar

I stället för ${} använd backticks ` [Knappen nedan Escape på tangentbordet.]

Kommentarer

  • Vänligen don ' använd inte backticks. Använd kommandosubstitution. $( ... )
  • De är föråldrade, de är svåra att läsa, de <

t häckar och de kan alltid ersättas med parantesbyte. Dessutom är de svåra att placera i inbyggda kodblock på de flesta markdown-språk 🙂

  • Ja, det stämmer. Men när det gäller den här frågan, var gick mitt svar fel ??
  • Du föreslog att använda backticks.
  • @Jesse_b ' det finns gott om av skäl att inte använda backticks, men oförmågan att bo dem är inte en av dem: echo `echo \`echo hello\`` . Ja, det behöver fly, men det betyder bara att ' inte är lika lätt att bo som $(...), inte att det ' är omöjligt.
  • Svar

    Kommandosubstitution (rad 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 

    motsvarar, som redan påpekats, (rad 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 kortare (rad 4 borta, nu ekar direkt)

    for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done 

    och kommandot sed kan reduceras till (rad 3)

    for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done 

    eller kanske extrahera den mellersta 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 

    hitta nu iterator istället för for-iterator: (rad 1 till 3, 4 borta)

    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 

    Om dina filnamn finns i sådan eller liknande ordning kan följande också fungera:

    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 och 12 ingår, för att visa saknade filer i sekvensen).

    Lämna ett svar

    Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *