mauvaise substitution exécutant $ {ls … | sed …} avec bash

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

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

  • @Jesse_b, oui, mais si votre shell a <<<, il a probablement aussi ${var/pat/repl}. Si vous exécutez sed, vous pouvez simplement donner les deux règles à une instance sed: sed -e 's/assemblyDB\.//' -e 's/\.las//'
  • Je voulais juste pointez UUOE;)

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).

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *