ゼロ以外のバイトを取得できるように、/ dev / zeroにビットマスクを設定するにはどうすればよいですか?


20

/dev/zero0x00だけでなく、0x01から0xFFまでの任意のバイトのソースを取得できるように、ビットマスクを設定するにはどうすればよいですか?


8
なぜ聞くのですか?質問を編集して動機付けしてください。
バジルスタリンケビッチ

1
この回答を参照として使用できます:stackoverflow.com/questions/12634503/how-to-use-xor-in-bash
Romeo Ninov

私はこの質問に答えましたが、もう一度読んで、私はそれを誤解したと思います。それぞれ0x00を特定の値に変換し0x00-0xFFますか、それとも範囲内のランダムな値に変換しますか?
コス

1
@kos 444444...ランダムではないような特定の値にそれぞれ
エデュアルドフロリネスク

回答:


18

次のbashコードは、バイナリで表現されているバイトで動作するように設定されています。しかし、あなたは簡単に処理するためにそれを変更することができocatal小数六角を単に変更することにより、基数 r の値2 にする810または16それぞれとの設定b=に応じて。

r=2; b=01111110
printf -vo '\\%o' "$(($r#$b))"; </dev/zero tr '\0' "$o"

編集 - バイト値の全範囲を処理します:16進数 00 - FF(以下に00-7Fを書いたとき、シングルバイトUTF-8文字のみを検討していました)。

たとえば、4バイト(UTF-8 'ASCII'のみの16進数00-7Fの範囲の文字)のみが必要な場合は、headにパイプすることができます。... | head -c4

出力(4文字):

~~~~

出力を8ビット形式で表示するには、パイプxxd(またはその他の1と0のバイトダンプ*)にパイプし
ます。b=10000000および配管:... | head -c4 | xxd -b

0000000: 10000000 10000000 10000000 10000000                    ....

1
o=$(printf ...)2行目を書くつもりでしたか?
jwodder

1
@jwodder:いいえ、2行目は示されているとおりです。printf関数のオプションでは、-v直接の直後という名前の変数を設定するには間に合わない出力が発生します。この場合、変数の名前はo8進数の)- -vオプションは(/ usr / bin / printfバージョンではなく)シェル組み込みバージョンに適用されることに注意してくださいprintf
Peter.O

2
@jwodderまた、一般に、この-vオプションは変数が指定したとおりに設定されるようにします。$(...)最初に出力を変換します。これはなぜあるo=$(printf '\n')のに対し、あなたが期待するかもしれない影響を与えることはありませんprintf -vo '\n'ありません。(ここでの出力は、このような変換の影響を受けない形式であるため、ここでは重要ではありませんが、-vオプションを知らない場合、これは知っておくと便利です。)
hvd

18

簡単にはできません。

そのようなデバイスを提供する独自のカーネルモジュールを作成することを検討してください。私はそれをお勧めしません。

パイプ(またはstdout)またはFIFO に同じバイトの無限ストリームを書き込む小さなCプログラムを作成できます。

tr(1)を使用して/dev/zero、0バイトごとに読み取り、他のバイトに変換できます。

少なくとも改行を使用する余裕がある場合は、おそらくyes(1)を使用することができます(またはパイプでtr -d '\n'...)


10
または使用する yes 1 | tr -d $'\n'その問題にします。
小次郎

3
@kojiro:文字のyesストリームを試みると失敗します\n。ハンドルの選択肢は\n次のとおりです。yes '' | tr '\n' "$c"-どこ$cASCII文字の完全な範囲の任意の文字することができます。
Peter.O

1
@ Peter.Oコメントをどのように解釈して、リテラルの静的な表現以外のものを意味するのかわかりませんyes 1 | tr -d $'\n'$''バックスラッシュ処理を行わないシェルを使用したり、を変更するロケールを見つけようとしたりできると思いますがtr -d $'\n'、まだ見つかりません。
小次郎

@kojiro:文字のyes 1 | tr -d $'\n'ストリームと1他のほぼすべてのシングルバイト値をかなり喜んで印刷しますが、文字のストリームを印刷することはできません\n。OPは、「0x01と0xFFの間」の
-Peter.O

1
loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
PSkocik

13

まあ、文字通りこれを達成したい場合は、LD_PRELOADフックを使用できます。基本的な考え方は、Cライブラリの関数を書き換えて、通常の関数の代わりに使用することです。

次に、read()関数をオーバーライドして、出力バッファーを0x42とXOR する簡単な例を示します。

#define _GNU_SOURCE
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <dlfcn.h> 
#include <unistd.h>

static int dev_zero_fd = -1;

int open64(const char *pathname, int flags)
{
    static int (*true_open64)(const char*, int) = NULL;
    if (true_open64 == NULL) {
        if ((true_open64 = dlsym(RTLD_NEXT, "open64")) == NULL) {
            perror("dlsym");
            return -1;
        }        
    }
    int ret = true_open64(pathname, flags);
    if (strcmp(pathname, "/dev/zero") == 0) {
        dev_zero_fd = ret;
    }
    return ret;
}


ssize_t read(int fd, void *buf, size_t count)
{
    static ssize_t (*true_read)(int, void*, size_t) = NULL;
    if (true_read == NULL) {
        if ((true_read = dlsym(RTLD_NEXT, "read")) == NULL) {
            perror("dlsym");
            return -1;
        }        
    }    

    if (fd == dev_zero_fd) {
        int i;
        ssize_t ret = true_read(fd, buf, count);    
        for (i = 0; i < ret; i++) {
            *((char*)buf + i) ^= 0x42;
        }
        return ret;
    }

    return true_read(fd, buf, count);    
}

単純な実装では、読み取るすべてのファイルに対してXOR 0x42が実行され、望ましくない結果が生じます。この問題を解決するために、 open()関数 / dev / zeroに関連付けられたファイル記述子をフェッチするようにしました。次に、read()関数でXORのみを実行しますfd == dev_zero_fd

使用法:

$ gcc hook.c -ldl -shared -o hook.so
$ LD_PRELOAD=$(pwd)/hook.so bash #this spawns a hooked shell
$ cat /dev/zero
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

3
実装を考えると、/ dev / capbeeから/ dev / zeroへのシンボリックリンクを作成し、/ dev / capbeeを検索して、/ dev / zeroをそのままにしておくことができます。// dev / zeroは/ dev / zeroと同じではありません。
ロバートジェイコブス

1
@RobertJacobs確かに。/ dev / 0x01、/ dev / 0x02、/ dev / 0x03、...へのシンボリックリンクを生成し、ファイル名を解析して適用するビットマスクを決定することもできます。
yoann

11

速度の観点から、私が見つけた最速は:

$ PERLIO=:unix perl -e '$s="\1" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]

比較のために:

$ tr '\0' '\1' < /dev/zero | pv -a > /dev/null
[ 765MiB/s]
$ busybox tr '\0' '\1' < /dev/zero | pv -a > /dev/null
[ 399MiB/s]

$ yes $'\1' | tr -d '\n' | pv -a > /dev/null
[26.7MiB/s]

$ dash -c 'while :; do echo -n "\ 1"; 完了」| pv -a> / dev / null
[225KiB / s]
$ bash -c 'while :; echo -ne "\ 1"; 完了」| pv -a> / dev / null
[180KiB / s]

$ < /dev/zero pv -a > /dev/null
[5.56GiB/s]
$ cat /dev/zero | pv -a > /dev/null
[2.82GiB/s]

私のDebianでは、perl2.13GiBを< /dev/zero生成し、8.73GiB を生成します。どのようなことがパフォーマンスに影響しますか?
cuonglm

@cuonglm、はい、システム間に多少の違いが見られますがperl、他のソリューションより一貫して高速です。同等のコンパイル済みCプログラムと同じスループットが得られます。ベンチマークは、ここにあるシステムのスケジューラーと同じくらいアプリケーションにあります。最も異なるのは、書き込まれるバッファのサイズです。
ステファンシャゼル

@cuonglmパイプもそれを遅くします。cat /dev/zero| pv -a >/dev/null毎秒約2 GiBが得られると思います(私のシステムで< /dev/zeroはそうですが、約6GiBpsになります)。
PSkocik

@StéphaneChazelasステファンシャゼラス、あなたはどんなシステムをお使いですか?私の結果はかなり異なります(perlバージョンから2.1GiBを得ることができます)。私は上だLinux ProBook 3.13.0-24-generic #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU/Linuxインテルi5のコアの内部。
PSkocik

1
@ PSkocik、Linux 3.16.0-4-amd64#1 SMP Debian 3.16.7-ckt9-3(2015-04-23)x86_64 GNU / Linux、Intel(R)Core(TM)2 Duo CPU T9600 @ 2.80GHz。:新しいカーネルは(v5.20.2それは、より新しいPerlのない限り)違いを作るように見える
ステファンChazelas

7

ビットマスク/ xorゼロバイトを試してみても意味がありませんよね?バイトを取り、xorゼロでそれを実行することは何もしません。

必要なバイトを提供するループを作成し、パイプまたは名前付きパイプの背後に配置するだけです。キャラクターデバイスとほぼ同じように動作します(アイドル時にCPUサイクルを浪費しません):

mkfifo pipe
while : ; do echo -n "a"; done > pipe &

また、最適化する場合は、以下のCコードを使用できます。

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) { 
  char c = argc == 1+1 ? argv[1][0] : 'y';

  char buff[BUFSIZ];
  memset(buff, c, BUFSIZ);

  for(;;){ 
    write(1, buff, sizeof(buff)); 
  }
}

コンパイルして実行

$ CFLAGS=-O3 make loop
./loop "$the_byte_you_want" > pipe

性能テスト:

./loop 1 | pv -a >/dev/null 

私のマシンでは2.1GB / s(さらにわずかに速いcat /dev/zero | pv -a >/dev/null


元々Cでputcharを使用しようとしましたが、時間がかかりました。
PSkocik

好奇心から、なぜではargc == 1+1なくagrc == 2
モニカiamnotmaynardを

@iamnotmaynardコマンドラインの実行可能ファイルが1で、引数が1であることを思い出してください。:-D
PSkocik

あ。それは私の推測でしたが、秘密の理由がないことを確認したかったのです。
モニカiamnotmaynardを

「バイトを取得し、ゼロでxorすることは何もしません。」これは正しくありません:0 XOR X == X
ジャクワー

5

ゼロを読み取り、各ゼロをパターンに変換します!

から0バイトを読み取り/dev/zerotr各ゼロバイトを変換して各バイトにビットマスクを適用します。

$ </dev/zero tr '\000' '\176' | head -c 10
~~~~~~~~~~$

Octal 176はASCIIコードで~あるため、10を取得し~ます。($出力の最後に、シェルで行の終わりがなかったことが示されています-あなたにとっては違って見えるかもしれません)

それでは、0xFFバイトを作成しましょう。Hex 0xFFは8進数0377です。trコマンド行の先頭のゼロは省略されます。最後にhexdump、出力を読み取り可能にするために使用されます。

$ </dev/zero tr '\000' '\377' | head -c 10 | hexdump
0000000 ffff ffff ffff ffff ffff               
000000a

ここでは、16進数の代わりに、文字の8進数コードを使用する必要があります。したがって、範囲は\0008進数から8進数です\377(と同じ0xFF)。およびを
使用ascii -xascii -oて、16進数または8進数のインデックス番号を持つ文字のテーブルを取得します。
(10進数と16進数のテーブルの場合、ちょうどascii)。

かなり速いです

ゼロを使​​用するのに比べて、かなり高速に実行されますcat /dev/zero。IOバッファリングを完全に使用できますが、trできません。

$ </dev/zero tr '\000' '\176' | pv -a >/dev/null
[ 913MB/s]

$ </dev/zero cat | pv -a >/dev/null        
[4.37GB/s]

3

データをどのように処理するか、およびデータをどの程度柔軟に使用するかによって異なります。

最悪の場合、速度が必要な場合は、/ dev / zeroと同じ操作を行い、/ dev / one、/ dev / two、.. / dev / fourtytwo ..などのデバイスをコンパイルするだけで済みます。

ほとんどの場合、データを必要な場所に直接作成する方がよいはずです。そのため、定数としてプログラム/スクリプト内に作成します。より多くの情報があれば、人々はあなたをよりよく助けることができます。


1

Infinte printfループ

必要な\u00バイトに置き換えます。

while true ; do printf "\u00" ; done | yourapp

C ++コード:

#include<cstdio>

int main(){
 char out=Byte;
 while(true)
 fwrite(&out,sizeof(out),1,stdout);
}

コンパイル:必要なByte値に置き換えます。

g++ -O3 -o bin file.cpp -D Byte=0x01

つかいます

./bin | yourapp

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.