Comment utiliser $ variable dans une extension d'accolade d'une séquence?


33

Je veux utiliser $var inune extension de coque shell avec une plage, en bash. Mettre simplement {$var1..$var2}ne fonctionne pas, alors je suis allé "latéralement" ...

Ce qui suit fonctionne, mais c'est un peu kludgey.

# remove the split files
echo rm foo.{$ext0..$extN} rm-segments > rm-segments
source rm-segments

Y a-t-il une manière plus "normale"?

Réponses:


26

Vous voudrez peut-être essayer:

eval rm foo.{$ext0..$extN}

Pas sûr que ce soit la meilleure réponse, mais c’est certainement le cas.


Durrh! :( Je ne pouvais pas voir l'évidence ... Merci :)
Peter.O

4
Dans bash, {} expansion est antérieure à $ expansion, donc je ne pense pas qu'il soit possible de faire cela autrement qu'en utilisant eval ou une autre astuce pour provoquer deux passages dans l'expression.
Mattdm

6
Je viens de le "comprendre"! ... Il n'y a pas d'expansion d'accolade avec {$one..$three}, car ce n'est pas une forme d'expansion d'accolade valide, qui dans ce cas attend des entiers ... Elle ne devient une forme valide qu'après l'expansion de $ var, qui evalpasse ensuite par le même processus pour générer un développement de séquence d’accolade normal ... 1 2 3 QED;) ... Résumé: la simple présence d’une paire d’accolade ne déclenche pas le développement de l’accolade ... seule une forme valide le déclenche .
Peter.O

@fred: Bienvenue :-)
asoundmove

Lorsque vous utilisez une variable comme a={0..9}; echo $a;il n’y a pas d’ extension d’accolade . En utilisant eval, ça marche. Je pense donc que l'explication de @ mattdm est bonne.
dr0i

20

Comme vous vous êtes déjà rendu compte, {1..3}s’agrandit 1 2 3mais ne déclenche pas {foo..bar}ou {$foo..$bar}ne développe pas l’accolade. Cette dernière est ensuite étendue pour remplacer $fooet $barpar leurs valeurs.

Un repli sur GNU (par exemple, Linux non intégré) est la seqcommande.

for x in `seq $ext0 $extN`; do rm foo.$x; done

Une autre possibilité. si foo.ne contient aucun caractère spécial de shell, est

rm `seq $ext0 $extN | sed 's/^/foo./'`

La solution la plus simple consiste à utiliser zsh, d'où rm foo.{$ext0..$extN}vient ce que vous voulez.


Merci pour les options .. C’est bien de les voir tous groupées .. Je vais rester avec bash et eval ... eval est assez simple maintenant que je sais ce qui se passe dans les coulisses; donc ce n'est plus un problème. Pas besoin de changer un bon cheval à cause du cavalier
:)

1

Tandis que les autres réponses expliquent comment utiliser evalet seq, dans bash, vous pouvez utiliser une forboucle de style C traditionnelle dans un contexte arithmétique. Les variables ext0et extNsont développées à l'intérieur, ce qui ((..))provoque l'exécution de la boucle pour la plage définie.

for (( idx = ext0; idx <= extN; idx++ )); do
    [[ -f "$foo.$idx" ]] || { printf "file %s does not exist" "$foo.$idx" >&2 ; continue }
    rm "$foo.$idx"
done

Si vous recherchez un moyen optimal et évitez les multiples rm commandes , vous pouvez utiliser un espace réservé temporaire pour stocker les résultats du nom de fichier et appeler rmone-shot.

 results=()
 for (( idx = ext0; idx <= extN; idx++ )); do
     [[ -f "$foo.$idx" ]] || { printf "file %s does not exist" "$foo.$idx" >&2 ; continue }
     results+=( "$foo.$idx" )
 done

et maintenant appeler la rmcommande sur le tableau développé

 rm -- "${results[@]}"

0
    function f_over_range {
        for i in $(eval echo {$1..$2}); do
            f $i
        done
    }

    function f {
        echo $1
    }

    f_over_range 0 5
    f_over_range 00 05

Remarques:

  • L'utilisation de eval expose le risque de sécurité d'injection de commande
  • Linux imprimera "00 \ n01 \ n02..etc", mais OSX imprimera "1 \ n2 \ n ... etc"
  • L'utilisation de seq ou de style C pour les boucles ne correspond pas à la gestion des zéros non significatifs par le mode expansion
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.