如何设置位掩码,/dev/zero
以便不仅可以获取0x00的源,还可以获取0x01和0xFF之间的任何字节的源?
0x00
值转换为特定值还是0x00-0xFF
范围内的随机值?
444444...
而不是随机值
如何设置位掩码,/dev/zero
以便不仅可以获取0x00的源,还可以获取0x01和0xFF之间的任何字节的源?
0x00
值转换为特定值还是0x00-0xFF
范围内的随机值?
444444...
而不是随机值
Answers:
以下bash
代码设置为以二进制表示的字节起作用。但是你可以很容易地改变它处理ocatal,十进制或十六进制通过简单地改变基数 r
的价值2
来8
,10
或16
分别设置b=
相应。
r=2; b=01111110
printf -vo '\\%o' "$(($r#$b))"; </dev/zero tr '\0' "$o"
编辑 -它确实处理所有范围的字节值:十六进制 00 - FF(当我在下面编写00-7F时,我只考虑了单字节UTF-8字符)。
例如,如果您只需要4个字节(仅UTF-8'ASCII'十六进制00-7F范围内的字符),则可以将其传送到head中:... | head -c4
输出(4个字符):
~~~~
看在8位格式的输出,管道将它导入xxd
(或任何其他的1和0的字节转储*):
例如。b=10000000
并输送至:... | head -c4 | xxd -b
0000000: 10000000 10000000 10000000 10000000 ....
o=$(printf ...)
第二行吗?
-v
导致里边反输出直接设置后立即命名变量; 在这种情况下,变量的名称为o
(八进制)-请注意,该-v
选项适用于shell内置版本printf
(不适用于/ usr / bin / printf版本)
-v
选项还可以确保将变量设置为恰好指定的值。$(...)
首先转换输出。这就是为什么o=$(printf '\n')
不会产生您期望的效果,而却printf -vo '\n'
如此的原因。(此处无关紧要,因为此处的输出格式不受这种转换的影响,但是如果您不知道该-v
选项,那么可能会很有用。)
您不能轻易做到这一点。
您可能会考虑编写自己的提供此类设备的内核模块。我不建议那样。
您可以编写一个微型C程序,在某个管道(或stdout
)或FIFO 上写入相同字节的无限流。
你可以用 tr(1)读取/dev/zero
每个0字节并将其转换为其他内容。
您可以使用yes(1),至少在您负担得起换行符的情况下(或将其换成tr -d '\n'
...)
yes 1 | tr -d $'\n'
为此使用。
yes
流,那将失败\n
。处理的替代方法\n
是:yes '' | tr '\n' "$c"
–哪里$c
可以是所有ASCII字符范围的任何char。
yes 1 | tr -d $'\n'
。我想您可以使用一个不进行$''
反斜杠处理的外壳,或者您可以尝试找到一个可以改变的语言环境tr -d $'\n'
,但是我还没有找到它。
yes 1 | tr -d $'\n'
将很愉快地打印1
字符流和几乎所有其他单字节值,但是它不能打印\n
字符流。OP希望能够处理“ 0x01和0xFF之间”的
loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
好吧,如果您确实想实现此目标,则可以使用 LD_PRELOAD挂钩。基本思想是从C库重写一个函数,然后使用它代替常规函数。
这是一个简单的示例,其中我们重写read()函数以将输出缓冲区与0x42异或。
#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
在速度方面,我发现最快的是:
$ 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]
$破折号-c'while:; 做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]
perl
产量为2.13GiB,而< /dev/zero
产量为8.73GiB。哪些因素会影响性能?
perl
始终比其他解决方案快。我得到与等效的编译C程序相同的吞吐量。基准测试在应用程序上与在系统的调度程序上一样多。最不同的是要写入的缓冲区的大小。
cat /dev/zero| pv -a >/dev/null
每秒也会为您提供大约2 GiBs(它在我的系统上确实达到了,而< /dev/zero
)也使我大约达到6GiBps。
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
Intel i5 Core。
尝试将位掩码/异或为零字节是没有意义的,不是吗?取一个字节并将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
)
argc == 1+1
代替agrc == 2
?
0 XOR X == X
。
我们从中读取零字节/dev/zero
,并tr
通过转换每个零字节来对每个字节应用位掩码:
$ </dev/zero tr '\000' '\176' | head -c 10
~~~~~~~~~~$
八进制176是的ASCII码~
,因此我们得到10 ~
。($
输出末尾的表示我的外壳中没有行尾-对您来说它可能看起来有所不同)
因此,让我们创建0xFF
字节:十六进制0xFF
为八进制0377
。tr
命令行的前导零被忽略了;最后,hexdump
用于使输出可读。
$ </dev/zero tr '\000' '\377' | head -c 10 | hexdump
0000000 ffff ffff ffff ffff ffff
000000a
您需要在此处使用字符的八进制代码,而不是十六进制。因此,范围是从\000
到八进制\377
(与相同0xFF
)。
使用ascii -x
和ascii -o
获取具有十六进制或八进制索引号的字符表。
(对于具有十进制和十六进制的表,仅为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]