Bash:制御値をバイナリに保つバイナリ範囲を持つForループ

Bash:制御値をバイナリに保つバイナリ範囲を持つForループ

バイナリ値を含む2つのbash変数があるとします。

a=0011 # decimal 3
b=1000 # decimal 8

$a可能なすべての値を繰り返し$bバイナリに保つ方法はありますか?それは次のとおりです。

for blah in $(seq $a $b) ; do
    print "Blah is: $blah"
done

したがって、次のように出力されます。

Blah is: 0011
Blah is: 0100
Blah is: 0101
Blah is: 0110
Blah is: 0111
Blah is: 1000

私は試した:

for blah in $(seq "$((2#$a))" "$((2#$b))") ; do

しかし、$blah10進数になり、2進数で維持したいと思います。 (いつでも10進数を2進数に変換できますが、すでに厳しいバイナリ)

コードは限られたLinux(オープンWRT)使用できませんobase。答えがこの場合バイナリ値を保存することは不可能です、これはまた便利な答えです(を使用せずに10進数を2進数に変換する関数を作成することができますobase)も一般的ですbash

答え1

あなたはこれにかなり近いです:

for blah in $(seq "$((2#$a))" "$((2#$b))") ; do

for同様の方法を使用して、ループ内の10進値を再び2進数に変換しますdc

はい

$ for blah in $(seq "$((2#0011))" "$((2#1000))"); do \
     printf "%04d\n" $(echo "obase=2;$blah" | bc);done
0011
0100
0101
0110
0111
1000

printf前にゼロが埋め込まれ、特定の幅にフォーマットされているように出力を制御するために使用されます。パラメーターは%04d出力内容を指定します。

このコマンドのもう1つの重要な点は、bcコマンドライン電卓を使用することです。このコマンドの例は次のとおりです。

echo "obase=2;$blah" | bc

を使用して値を取得し、$blah2進数(2進数とも呼ばれる)に変換しますbc

BCまたはDCなし

これらのツールがまったく存在しないように制限されたシステムを使用している場合は、awkマニュアルのこの機能を直接使用して変換できます。awk

はい

次の内容でファイルを作成し、名前をdec2bin.awk

# bits2str --- turn a byte into readable 1's and 0's

function bits2str(bits, data, mask)
{
    if (bits == 0)
        return "0"

    mask = 1
    for (; bits != 0; bits = rshift(bits, 1))
        data = (and(bits, mask) ? "1" : "0") data

    while ((length(data) % 8) != 0)
        data = "0" data

    return data
}

{
  printf("%s\n", bits2str($1))
}

さて、上記の機能を使用してください。

$ for blah in $(seq "$((2#0011))" "$((2#1000))"); do echo $blah \
     | awk -f dec2bin.awk; done
00000011
00000100
00000101
00000110
00000111
00001000

答え2

seq内蔵されていません。また、Posix 標準の一部ではありません。ただし、一般的な実装では、seq10 以外の基準でソートする機能はありません。

Bashでは範囲を{start..finish}{a..f}a b c d e f

私が知る限り、これはいくつかの可能性を提供する単純なシーケンスジェネレータです。

愚かな方法は、バイナリではなく値をフィルタリングすることです。a合計がb非常に小さくはありませんが、非常に非効率的であれば、これは簡単です。

for x in $(seq -w $a $b); do
  if [[ ! ($x =~ [2-9]) ]]; then
    echo $x
  fi
done

これがより良い解決策です。aとの長さが同じであると仮定するとb(そうでない場合はprintfを使用してこの問題を解決できます)、以下はaからb(含む)までのすべての2進数を繰り返します。

# We need a string of 0s at least as long as a:
z=${a//1/0}
while [[ ! ($a > $b) ]]; do
  # do something with $a
  # The following "increments" a by removing the last 0 (and trailing 1s)
  # and replacing that with a 1 and the same number of 0s.
  a=$(printf "%.*s" ${#a} ${a%0*}1$z)
done

答え3

以下を使用する方が簡単ですzsh

for ((i=2#$a; i<=2#$b; i++)) echo $(([##2]i))

または 0 パディングを使用します。

for ((i=2#$a; i<=2#$b; i++)) printf '%04d\n' $(([##2]i))

それ以外の場合は、次のものを使用できますbc

echo "ibase=obase=2; for (i=$a; i<=$b; i++) i" | bc

またはdc:

echo "2doi $a [p1+d$b!<a]dsax" | dc

0-padの場合、常に出力を次にパイプできます。

sed 's/^/000/;s/^0*\(.\{4\}\)/\1/'

答え4

この方法は多くの処理を実行するため、大規模には適していません。

seq -f '%04g' 0011 1000 | grep -v '[2-9]'

関連情報