Как я могу надеть битовую маску, /dev/zero
чтобы иметь источник не только для 0x00, но и для любого байта между 0x01 и 0xFF?
0x00
к определенному значению или к случайному значению в 0x00-0xFF
диапазоне?
444444...
не случайному
Как я могу надеть битовую маску, /dev/zero
чтобы иметь источник не только для 0x00, но и для любого байта между 0x01 и 0xFF?
0x00
к определенному значению или к случайному значению в 0x00-0xFF
диапазоне?
444444...
не случайному
Ответы:
Следующий bash
код настроен для работы с байтом, представленным в двоичном виде . Однако вы можете легко изменить его для обработки ocatal , десятичного или шестигранника , просто изменяя базисное r
значение 2
для 8
, 10
или , 16
соответственно , и установки b=
соответственно.
r=2; b=01111110
printf -vo '\\%o' "$(($r#$b))"; </dev/zero tr '\0' "$o"
РЕДАКТИРОВАТЬ - Он обрабатывает полный диапазон значений байтов: hex 00 - FF (когда я писал ниже 00-7F, я рассматривал только однобайтовые символы UTF-8).
Если, например, вы хотите только 4 байта (символы в диапазоне UTF-8 «ASCII' только шестигранный 00-7F) , вы можете конвейеру в голову :... | head -c4
Выход (4 символа):
~~~~
Чтобы увидеть вывод в 8-битном формате, направьте его в xxd
(или любой другой байтовый дамп 1 и 0 *):
например. b=10000000
и трубопровод к:... | head -c4 | xxd -b
0000000: 10000000 10000000 10000000 10000000 ....
o=$(printf ...)
для второй строки?
-v
вызывает Лобовой выход непосредственно установить переменную сразу после него; в этом случае имя этой переменной o
(для восьмеричного ) - обратите внимание, что этот -v
параметр применяется к встроенной в оболочку версии printf
(не к версии / usr / bin / printf )
-v
опция гарантирует, что переменная будет установлена точно в соответствии с тем , что вы указали. $(...)
сначала преобразует вывод. Вот почему o=$(printf '\n')
не будет иметь эффекта, которого вы можете ожидать, в то время как printf -vo '\n'
да. (Это не имеет значения, поскольку выходные данные представлены в форме, не подверженной такому преобразованию, но если вы не знали об этой -v
опции, это может быть полезно знать.)
Вы не можете легко сделать это.
Вы можете написать свой собственный модуль ядра с таким устройством. Я не рекомендую это.
Вы можете написать крошечную C-программу, записывающую бесконечный поток одних и тех же байтов в какой-либо канал (или в stdout
) или FIFO.
Вы можете использовать tr (1) для чтения /dev/zero
и перевода каждого 0 байта в другое.
Вы могли бы использовать, возможно, да (1) , по крайней мере, если вы можете позволить себе переводы строки (или еще трубку в tr -d '\n'
...)
yes 1 | tr -d $'\n'
в этом отношении.
yes
поток \n
символов. Альтернатива, которая обрабатывает \n
: yes '' | tr '\n' "$c"
- где $c
может быть любой символ из полного диапазона символов ASCII.
yes 1 | tr -d $'\n'
. Я полагаю, вы могли бы использовать оболочку, которая не выполняет $''
обработку обратной косой черты, или вы можете попытаться найти локаль, которая изменяет tr -d $'\n'
, но я пока не нашел ее.
yes 1 | tr -d $'\n'
радостью напечатаете поток 1
символов и почти все другие однобайтовые значения, но он не сможет напечатать поток \n
символов. ОП хочет иметь возможность обрабатывать все байтовые значения «между 0x01 и 0xFF»
loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
Что ж, если вы в буквальном смысле хотите этого добиться, вы можете использовать ловушку LD_PRELOAD . Основная идея заключается в том, чтобы переписать функцию из библиотеки C и использовать ее вместо обычной.
Вот простой пример, где мы переопределяем функцию read () для XOR выходного буфера с 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. Тогда мы только выполняем XOR в нашей функции read (), если 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]
$ dash -c 'while:; do echo -n "\ 1"; сделано '| pv -a> / dev / null [225 КБ / с]
$ bash -c 'while:; do echo -ne "\ 1"; сделано '| pv -a> / dev / null [180 КБ / с]
$ < /dev/zero pv -a > /dev/null
[5.56GiB/s]
$ cat /dev/zero | pv -a > /dev/null
[2.82GiB/s]
perl
получите 2.13 ГБ, а < /dev/zero
8.73 ГБ. Что может повлиять на производительность?
perl
всегда быстрее, чем другие решения. Я получаю ту же пропускную способность, что и с эквивалентной скомпилированной C-программой. Этот тест для приложения так же важен, как и для системного планировщика. Что отличает больше всего, так это размер записываемых буферов.
cat /dev/zero| pv -a >/dev/null
что даст вам около 2 ГиБ в секунду (это происходит в моей системе, в то время как < /dev/zero
) дает мне около 6 ГБ / с.
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 нулевых байтов, не так ли? Взять байт и xor
записать его с нуля - нет.
Просто создайте цикл, который даст вам нужные байты, и поместите его за канал или именованный канал. Он будет вести себя почти так же, как символьное устройство (не будет тратить циклы ЦП во время простоя):
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,1 ГБ / с на моей машине (даже немного быстрее, чем 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
~~~~~~~~~~$
Octal 176 - это код ascii ~
, поэтому мы получаем 10 ~
. (В $
конце вывода указывает, что в моей оболочке не было конца строки - он может выглядеть по-другому для вас)
Итак, давайте создадим 0xFF
байты: Hex 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
он всего в четыре раза быстрее, в то время как он может идеально использовать буферизацию ввода-вывода, что tr
невозможно.
$ </dev/zero tr '\000' '\176' | pv -a >/dev/null
[ 913MB/s]
$ </dev/zero cat | pv -a >/dev/null
[4.37GB/s]
Зависит от того, что вы хотите сделать с данными и насколько гибко вы хотите их использовать.
В худшем случае, если вам нужна скорость, вы можете сделать то же самое, что и / dev / zero, и просто скомпилировать / dev / one, / dev / two, .. / dev / fourtytwo .. и другие устройства.
В большинстве случаев лучше создавать данные непосредственно там, где это необходимо, то есть внутри программы / скрипта как константы. С большим количеством информации люди могли бы лучше помочь вам.
Infinte printf loop
Заменить \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