Як я можу нанести трохи маски на / dev / zero, щоб я міг отримати байти, окрім нуля?


20

Як я можу надіти трохи маски, /dev/zeroщоб я міг мати джерело не тільки для 0x00, але і для будь-якого байту між 0x01 та 0xFF?


8
Чому Ви запитуєте? Відредагуйте питання, щоб мотивувати його.
Базиль Старинкевич

1
Ви можете використовувати цей відповідь в якості посилання: stackoverflow.com/questions/12634503/how-to-use-xor-in-bash
Romeo Нін

Я дав відповідь на це питання, але прочитавши його ще раз, думаю, що я його зрозумів неправильно. Ви хочете перевести кожне 0x00на певне значення або на випадкове значення в 0x00-0xFFдіапазоні?
kos

1
@kos кожен до певного значення, як 444444...не випадкове
Едуард Флоринеску,

Відповіді:


18

Наступний 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                    ....

1
Ви мали на увазі написати o=$(printf ...)для другого рядка?
jwodder

1
@jwodder: Ні, другий рядок правильний, як показано. Printf опція -vвикликає Лобовий вихід безпосередньо встановити змінну відразу після нього; у цьому випадку ім'я цієї змінної o(для восьмеричного ) - зауважте, що ця -vопція застосовується до вбудованої оболонки версії printf(не до версії / usr / bin / printf )
Peter.O

2
@jwodder Також, загалом, ця -vопція гарантує, що змінна буде встановлена саме на те , що ви вказали. $(...)перетворює вихід спочатку. Ось чому o=$(printf '\n')не матиме ефекту, якого ви могли б очікувати, тоді як printf -vo '\n'. (Тут не має значення, оскільки вихід тут знаходиться у формі, на яку не впливає така трансформація, але якщо ви не знали про цей -vваріант, то це може бути корисно знати.)
hvd

18

Ви не можете легко зробити це.

Ви можете розглянути можливість створення власного модуля ядра, що забезпечує такий пристрій. Я не рекомендую цього.

Ви можете написати крихітну програму C, яка записує нескінченний потік однакових байтів на якусь трубу (або на stdout ) або FIFO.

Ви можете використовувати tr (1) для читання /dev/zeroта перекладу кожні 0 байт у щось інше.

Ви можете використати, можливо, так (1) , принаймні, якщо ви можете дозволити собі нові рядки (або інше передати його в tr -d '\n'...)


10
Або використовувати yes 1 | tr -d $'\n'для цього питання.
якийro

3
@kojiro: це не вдасться, якщо спробувати yesпотік \nсимволів. Альтернатива, якою обробляється, \nє: yes '' | tr '\n' "$c"- де $cможе бути будь-яка таблиця з усього діапазону символів ASCII.
Пітер.O

1
@ Peter.O Я не впевнений, як ти інтерпретував мій коментар нічого іншого, крім прямого, статичного вираження yes 1 | tr -d $'\n'. Я припускаю, що ви можете використовувати оболонку, яка не робить $''зворотну косу рису, або ви можете спробувати знайти місце, яке змінюється tr -d $'\n', але я ще не знайшов його.
якийro

@kojiro: yes 1 | tr -d $'\n'Ви з задоволенням надрукуєте потік 1символів і майже будь-яке інше однобайтове значення, але він не може надрукувати потік \nсимволів. ОП хоче мати можливість обробляти всі значення байтів "між 0x01 та 0xFF"
Peter.O

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

13

Ну, якщо ви буквально хочете цього досягти, ви можете використовувати гачок 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

3
З огляду на вашу реалізацію, ви можете мати символічне посилання від / dev / capbee до / dev / zero, шукати / dev / capbee та залишити / dev / zero у спокої. // dev / zero не буде таким же, як / dev / zero.
Роберт Джейкобс

1
@RobertJacobs Дійсно. Ми навіть можемо генерувати символьні посилання / dev / 0x01, / dev / 0x02, / dev / 0x03, ... to / dev / zero та аналізувати ім'я файлу, щоб визначити застосовану біт-маску.
Іоанн

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:; робити відлуння -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]

У моїй Debian, perlвихід 2.13GiB, а < /dev/zeroвихід 8.73GiB. Що може вплинути на продуктивність?
cuonglm

@cuonglm, так, я бачу деякі зміни між системами, але perlстабільно швидше, ніж інші рішення. Я отримую таку ж пропускну здатність, як і для еквівалентної складеної програми C. Орієнтовний показник стільки в застосуванні, скільки в планувальнику системи тут. Що найбільше відрізняється - це розмір написаних буферів.
Stéphane Chazelas

@cuonglm Труба також сповільнює її. Я думаю cat /dev/zero| pv -a >/dev/null, що ви також дасте близько 2 Гбіт в секунду (це робиться в моїй системі, поки < /dev/zero) дає мені близько 6 Гбіт / с.
PSkocik

@ StéphaneChazelas Чи можу я запитати, на якій системі ви працюєте, Стефане Шазелас? Результати на моїх досить різняться (я можу отримати приблизно 2.1GiB з версії perl). Я в 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/LinuxIntel i5 Core всередині.
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,80 ГГц. Нове ядро, здається, має значення (якщо тільки це не новіший: v5.20.2)
Stéphane Chazelas

7

Бути безглуздо намагатися байтувати маски / 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)


Спочатку я намагався використовувати путчар в С, але це було повільно.
PSkocik

Чому з цікавості, чому argc == 1+1замість цього agrc == 2?
Відновіть Моніку - немайнард

@iamnotmaynard Щоб нагадати собі, що це 1 для виконуваного командного рядка плюс 1 аргумент. :-D
PSkocik

Ага. Це було моє здогадка, але хотілося переконатися, що не було якоїсь таємної причини.
Відновіть Моніку - немайнард

"Взяти байт і закреслити його нулем - це неоперація." Це не так: 0 XOR X == X.
jacwah

5

Прочитайте нулі, перекладіть кожен нуль на свій шаблон!

Ми зчитуємо нульові байти з /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]

3

Залежить від того, що ви хочете зробити з даними та наскільки гнучко ви хочете їх використовувати.

Найгірший випадок, якщо вам потрібна швидкість, ви можете зробити те саме, що і / dev / zero, і просто скомпілювати / dev / one, / dev / two, .. / dev / fourrtytwo .. і так на інших пристроях.

У більшості випадків краще створити дані безпосередньо там, де це потрібно, тому всередині програми / сценарію як константа. Маючи більше інформації, люди можуть вам краще допомогти.


1

Інтенсивна петля 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.