Zobrazila se následující chyba:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
a toto je skript:
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done
Komentáře
- Co se snažíte dosáhnout pomocí rovnátek? Citujte také své proměnné.
- Viz Proč je smyčka přes find ' s výstupem špatná praxe?
Odpověď
${ ... }
(složené závorky) označuje několik druhy rozšiřování parametrů , nejjednodušší je pouze rozšíření hodnoty proměnné. Obsah uvnitř složených závorek ve vašem kódu není platný název parametru nebo jiné rozšíření, takže si shell stěžuje.
Zdá se, že místo toho chcete nahradit příkaz, proto je syntaxe $( ... )
(běžná závorka).
Také ls
v ls $filename | sed...
vypadá trochu zbytečné, proměnná se rozšíří na váš název souboru a ls
ji pouze předá. Místo toho můžete použít echo "$filename" | sed ...
.
To znamená, že tyto úpravy můžete provést přímo v shellu:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
nebo pomocí standardních operátorů:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
Pokud spustíte sed
, můžete si všimnout, že .
odpovídá jakémukoli znaku v regulárním výrazy, takže by bylo správnější citovat to zpětným lomítkem. Můžete také dát jedné sed
instanci oba příkazy: sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
A pak for filename in $(find . -type f -name "assemblyDB.*.las"); do
má všechny problémy parsování ls má, hlavně to, že mezery a zástupné znaky v názvech souborů to rozbijí. V ksh / Bash / zsh můžete udělat celou smyčku v shellu:
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
Komentáře
odpověď
místo ${}
použijte backticks `
[Tlačítko pod klávesou Escape na vaší klávesnici.]
Komentáře
- Prosím ' nepoužívejte zpětné lístky. Použijte substituci příkazu.
$( ... )
- Jsou zastaralé, těžko čitelné, ' se nehnízdí a nemohou vždy být nahrazen nahrazením příkazu v závorkách. Navíc je těžké je umístit do vložených bloků kódu ve většině značkovacích jazyků 🙂
- Ano, je to tak. Ale pokud jde o tuto otázku, kde se moje odpověď pokazila?
- Navrhli jste použít zpětné odkazy.
- @Jesse_b Existuje ' spousta důvodů, proč nepoužívat zpětné lístky, ale neschopnost je vnořit není jedním z nich:
echo `echo \`echo hello\``
. Ano, vyžaduje to únik, ale to prostě znamená, že ' není tak snadné vnořit jako$(...)
, ne to, že ' je nemožné.
Odpovědět
Náhrada příkazů (řádek 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
je ekvivalentní, jak již bylo uvedeno, (řádek 3, žádný 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
nebo kratší (řádek 4 zmizel, nyní se ozývá přímo)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done
a příkaz sed lze snížit do (řádek 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
nebo možná extrahujte střední část pomocí sed: (stále řádek 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
nyní find-iterator místo for-iterator: (řádek 1 až 3, 4 pryč)
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
Pokud jsou vaše názvy souborů v takové nebo podobné pořadí, může fungovat i následující:
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
(včetně 8 a 12, aby se ukázaly chybějící soubory v pořadí).
<<<
, má pravděpodobně také${var/pat/repl}
. Pokud spustíte sed, můžete obě pravidla dát jednésed
instanci:sed -e 's/assemblyDB\.//' -e 's/\.las//'