Bashブレース展開で変数を使用できますか?


10

以下は、私が達成しようとしていることに対するある種の疑似コードです:

#!/bin/bash

# I already have the variable below figured out (positive integer):
numlines=$([returns number of lines containing specific characters in a file])

# This is basically what I want to do with it:
for i in {1..$numlines}; do
    # the part below is already figured out as well:        
    do some other stuff
done

`{1..n} 'シーケンスに実際の数を挿入することで、コマンドラインから問題なく実行できます。ここに変数を含めることが可能かどうか、そしてそれを実行する方法を知る必要があるだけです。

  • 私はexportそれを試してみました
  • 変数自体をシーケンス内の中括弧に入れてみました: {1..${numlines}}
  • 私はそれが拡張することを期待して二重引用符でそれを入れてみました: {1.."$numlines"}
  • 私はエスケープしてみました${1..\$numlines}

set -[something]この変数を展開するためにコマンドを使用する必要がありますか?私はeval... を使っていくつかの形を試してみましたが、すべて役に立ちませんでした。

私が見逃している単純なものやあいまいなものがあるかどうか、またはこれ以上時間を無駄にする前にこれが可能かどうかを知る必要があるだけです。

本当にハックなやり方でまとめて、必要に応じて機能させることもできますが、できればそれを避けて、正しいやり方を学びたいと思います。


回答:


11

残念ながら、変数展開はブレース展開の後に行われるため、その展開(AFAIK)で変数を使用する方法はありません。

幸い、同じ仕事をするツールがあります。

for i in $(seq 1 $numlines); do
    # stuff
done

seqGNU coreutilsからです。POSIXでそれを行う方法はわかりません。


1
(プラス1)。 seqGNUシステムに適しています。正しく思い出せば、最新のOSXです。他のBSDシステムでは、代わりにjotを使用できます。
John1024 2015年

seq完璧に動作します。早速の回答ありがとうございます。
rubynorails

これは私の質問の一部ではありませんでした-しかし、これを逆の順序で行うための構文(ある場合)は{16..1}何ですか?$(seq $numlines 1)動作しませんでした。私はいつでもできると思いますがman seq、誰かが頭のてっぺんを知っているかどうか疑問に思っています。
rubynorails 2015年

1
ちょうどから逆にそれを行う方法を考え出し、このリンク -for i in $(seq $numlines -1 1)
rubynorails

seq ${numlines} -1 0
DopeGhoti

10

承知しました。もしループのインクリメント整数変数ことが必要な場合は、の形式を使用forループ(またはより一般的にループ変数(S)上の演算実行)をインクリメント整数変数こと。

for ((i=1; i<=numlines; i++)); do  done

この構成はbash(およびksh93とzsh)では機能しますが、プレーンなshでは機能しません。単純なshでは、whileループとtest([ … ])構文を使用します。

i=1
while [ "$i" -le "$numlines" ]; do
  
  i=$((i+1))
done

8

あなたが避けなければならない場合seq、これはトム・ハントがこれに対する通常の解決策であると思われるように、eval間違いなくそれ行うことができます(ただし、私はそれを奨励しません):

eval 'for i in {1..'$numlines'}; do echo $i; done'

{}展開を回避することでPOSIXのままで、単純に数学と整数の比較を行うことができます$numlines

while [ ! "$numlines" -eq 0 ]; do
     echo "$numlines"
     : $((numlines-=1))
done

POSIXの外bashkshそしてzshまたCスタイルのforループ:

for((i=0; i<numlines; i++)); do echo $i; done

1
私もこの回答に本当に感謝しています。一方でseq私のシナリオの罰金を働いて、最も簡単な解決策になるように見えた、他の(でもPOSIX)の選択肢があることを知っておくとよいです。これをありがとう。
rubynorails 2015年

2
実際に使用する理由はありませんeval。ブレース展開がある場合は、Cスタイルのループがあります。
chepner 2015年

@PSkocik-2つの回答を選択できる場合は、これも選択します。これを逆に行う必要があるという事実に出会ったとき、あなたのeval例は最も単純で、を使用してそれを行う別の方法を探す必要がなかったでしょうseqwhileループは私のためにビットかさばるです。私は物事を短くて甘いままにしておくのが好きで、0または1の値を指定してCスタイルのforループを機能させることはできiませんでした。正しく動作するように調整することはできると思いますが、それでも、これらは間違いなく役立つ解決策です。
rubynorails

evalループの本体の内部に重要なものが存在する場合、このアプローチには問題があります。このようなループを2つネストする必要がある場合は、あまり読みにくいと思います。
kasperd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.