Jai eu lerreur suivante:
./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution
et voici le script:
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done
Commentaires
- Quessayez-vous daccomplir avec les accolades? Citez également vos variables.
- Voir Pourquoi une boucle sur la sortie de find ' est-elle une mauvaise pratique?
Réponse
${ ... }
(accolades) marque plusieurs sortes d développement de paramètres , dont le plus simple est simplement de développer la valeur dune variable. Le truc entre accolades dans votre code nest pas « un nom de paramètre valide, ou toute autre extension, donc le shell se plaint.
Vous semblez vouloir la substitution de commande à la place, pour cela, la syntaxe est $( ... )
(parenthèses régulières).
De plus, le ls
dans ls $filename | sed...
semble un peu inutile, la variable se développe en votre nom de fichier et ls
la transmet simplement. Vous pouvez simplement utiliser echo "$filename" | sed ...
à la place.
Cela dit, vous pouvez effectuer ces modifications directement dans le shell:
no="${filename/assemblyDB.}" # remove first match no="${no/.las}"
ou, en utilisant les opérateurs standard:
no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string
Si vous exécutez sed
, vous pouvez noter que .
correspond à nimporte quel caractère expressions, il serait donc plus correct de le citer avec une barre oblique inverse. Vous pouvez également donner une sed
instance aux deux commandes: sed -e "s/assemblyDB\.//" -e "s/\.las//"
.
Et puis for filename in $(find . -type f -name "assemblyDB.*.las"); do
a tous les problèmes rencontrés par parsing ls , principalement le fait que les espaces et les caractères génériques dans les noms de fichiers le briseront. Dans ksh / Bash / zsh, vous pouvez faire toute cette boucle dans le shell:
shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ...
Commentaires
Réponse
Au lieu de ${}
utilisez des contre-indications `
[Le bouton ci-dessous Echap sur votre clavier.]
Commentaires
- Merci de ne pas ' t utiliser des contre-indications. Utilisez la substitution de commande.
$( ... )
- Ils sont obsolètes, ils sont difficiles à lire, ils ' ne semboîtent pas, et ils peuvent toujours être remplacé par la substitution de commande entre parenthèses. De plus, ils sont difficiles à placer dans des blocs de code en ligne sur la plupart des langages de démarquage 🙂
- Ouais, cest vrai. Mais en ce qui concerne cette question, où ma réponse a-t-elle mal tourné?
- Vous avez suggéré dutiliser des contre-indications.
- @Jesse_b Il y a beaucoup de ' des raisons de ne pas utiliser de backticks, mais limpossibilité de les imbriquer nen fait pas partie:
echo `echo \`echo hello\``
. Oui, il faut séchapper, mais cela signifie simplement que ' nest pas aussi facile à imbriquer que$(...)
, pas que cela ' est impossible.
Réponse
Substitution de commande (ligne 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
équivaut, comme déjà souligné, à (line 3, no 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
ou plus court (la ligne 4 a disparu, maintenant un écho directement)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done
et la commande sed peut être réduite à (ligne 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done
ou peut-être extraire la partie médiane avec sed: (toujours ligne 3)
for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done
maintenant find-iterator au lieu de for-iterator: (lignes 1 à 3, 4 disparues)
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
Si vos noms de fichiers sont dans tel ou un ordre similaire, ce qui suit peut également fonctionner:
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 et 12 inclus, pour démontrer les fichiers manquants dans la séquence).
<<<
, il a probablement aussi${var/pat/repl}
. Si vous exécutez sed, vous pouvez simplement donner les deux règles à une instancesed
:sed -e 's/assemblyDB\.//' -e 's/\.las//'