huono vaihto käynnissä $ {ls … | sed …} ja bash

Sain seuraavan virheen:

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

ja tämä on komentosarja:

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

kommentit

vastaus

${ ... } (kiharat) merkitsee useita erilaisten -parametrilaajennus , joista yksinkertaisin on vain muuttujan arvon laajentaminen. Koodisi aaltosulkeissa olevat tavarat eivät ole kelvollisia parametrinimiä tai muita laajennuksia, joten komentotulkki valittaa.

Näyttää siltä, että haluat sen sijaan komentojen korvaamisen, joten syntaksin arvo on $( ... ) (tavallinen sulu).

Myös ls kohdassa ls $filename | sed... näyttää hieman turha, muuttuja laajenee tiedostosi nimeen ja ls välittää sen vain. Voit käyttää vain echo "$filename" | sed ....

Tästä huolimatta voit tehdä nämä muutokset suoraan kuoressa:

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

tai käyttämällä vakio-operaattoreita:

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

Jos suoritat sed, kannattaa huomata, että . vastaa mitä tahansa merkkiä tavallisessa lausekkeita, joten olisi oikeampi lainata sitä vinoviivalla. Voit myös antaa yhden sed -esiintymän molemmat komennot: sed -e "s/assemblyDB\.//" -e "s/\.las//".

Ja sitten for filename in $(find . -type f -name "assemblyDB.*.las"); do sisältää kaikki ongelmat, jotka jäsennetään ls : llä, lähinnä se, että tiedostonimessä olevat tyhjät välit ja jokerit rikkovat sen. Ksh / Bash / zsh-tiedostossa voit tehdä tuon kokonaisen silmukan kuoressa:

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

Kommentit

  • @Jesse_b, kyllä, mutta jos kuoressasi on <<<, siinä on todennäköisesti myös ${var/pat/repl}. Jos suoritat sed-ohjelmaa, voit antaa molemmat säännöt yhdelle sed -esiintymälle: sed -e 's/assemblyDB\.//' -e 's/\.las//'
  • Halusin vain näytä UUOE;)

Vastaa

${} käytä backticks ` [Esc-näppäimen alla oleva painike.]

Kommentit

  • Älä ' t käytä backtickeja. Käytä komentojen korvaamista. $( ... )
  • ne ovat vanhentuneita, heitä on vaikea lukea, he eivät ' t pesää ja voivat aina korvataan suluilla komennon korvaaminen. Lisäksi niitä on vaikea sijoittaa inline-koodilohkoihin useimmilla markdown-kielillä 🙂
  • Joo, se on totta. Mutta mistä vastauksestani meni pieleen tähän kysymykseen?
  • Ehdotit backtickien käyttöä.
  • @Jesse_b Siellä ' on paljon syistä olla käyttämättä backtickeja, mutta kyvyttömyys sijoittaa ne ei ole yksi niistä: echo `echo \`echo hello\`` . Kyllä, se vaatii pakenemista, mutta se tarkoittaa vain sitä, että ' ei ole yhtä helppo pesiä kuin $(...), eikä sitä, että se ' on mahdotonta.

vastaus

Komennon korvaaminen (rivi 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 

vastaa, kuten jo todettiin, (rivi 3, ei 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 

tai lyhyempi (rivi 4 mennyt, nyt kaikuva suoraan)

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

ja sed -komentoa voidaan vähentää (rivi 3)

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

tai ehkä pura keskiosa sedillä: (silti rivi 3)

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

nyt find-iterator for-iteratorin sijaan: (rivit 1-3, 4 mennyt)

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 

Jos tiedostonimet ovat tällainen tai vastaava järjestys, myös seuraava saattaa toimia:

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 

(Mukana 8 ja 12, jotta voidaan näyttää puuttuvat tiedostot sarjasta).

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *