Як я можу надіти трохи маски, /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"
EDIT - Він обробляє весь діапазон значень байтів: hex 00 - FF (коли я писав 00-7F нижче, я розглядав лише однобайтові символи UTF-8).
Якщо, наприклад, вам потрібно лише 4 байти (символи в шестигранному діапазоні 00-7F, призначені лише для UTF-8 "ASCII") , ви можете передати це в голову :... | 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 . Основна ідея - переписати функцію з бібліотеки С і використовувати її замість звичайної.
Ось простий приклад, коли ми перекриваємо функцію 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:; робити відлуння -n "\ 1"; зроблено '| pv -a> / dev / null [225 Кбіт / с]
$ bash -c 'while:; робити відлуння -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.13GiB, а < /dev/zero
вихід 8.73GiB. Що може вплинути на продуктивність?
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
його до нуля - це неоперація.
Просто створіть цикл, який дає вам потрібні байти, і покладіть його за трубу або назву pipe. Він буде поводитись так само, як і символьний пристрій (не витрачає цикли процесора під час простою):
mkfifo pipe
while : ; do echo -n "a"; done > pipe &
І якщо ви хочете переоптимізувати його, ви можете використовувати код С нижче:
#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
~~~~~~~~~~$
Октал 176 - код асції ~
, тому ми отримуємо 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 / fourrtytwo .. і так на інших пристроях.
У більшості випадків краще створити дані безпосередньо там, де це потрібно, тому всередині програми / сценарію як константа. Маючи більше інформації, люди можуть вам краще допомогти.
Інтенсивна петля 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