ฉันจะใส่ bit mask อย่างไรใน / dev / zero เพื่อที่ฉันจะได้รับ bytes นอกเหนือจากศูนย์?


20

ฉันจะใส่บิตมาสก์ได้อย่างไร/dev/zeroเพื่อให้สามารถมีแหล่งที่มาไม่เพียง แต่สำหรับ 0x00 แต่ยังสำหรับไบต์ระหว่าง 0x01 ถึง 0xFF ด้วย?


8
คุณถามทำไม? โปรดแก้ไขคำถามเพื่อกระตุ้น
Basile Starynkevitch

1
คุณสามารถใช้คำตอบนี้เป็นข้อมูลอ้างอิง: stackoverflow.com/questions/12634503/how-to-use-xor-in-bash
Romeo Ninov

ฉันให้คำตอบสำหรับคำถามนี้ แต่อ่านอีกครั้งฉันคิดว่าฉันคิดถึงมัน คุณต้องการแปลแต่ละ0x00ค่าเป็นค่าเฉพาะหรือเป็นค่าสุ่มใน0x00-0xFFช่วงหรือไม่
kos

1
@ kos แต่ละรายการมีค่าเฉพาะ444444...ไม่ใช่แบบสุ่ม
Eduard Florinescu

คำตอบ:


18

ต่อไปนี้bashรหัสถูกตั้งค่าให้ทำงานร่วมกับไบต์ที่ถูก representred ในไบนารี แต่คุณสามารถเปลี่ยนมันในการจัดการocatal , ทศนิยมหรือหกเหลี่ยมโดยเพียงแค่การเปลี่ยนRadix 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 ไบต์(อักขระในช่วง 00-7F hex ของ UTF-8 'ASCII'-only hex เท่านั้น)คุณสามารถไพพ์ไว้ในส่วนหัวได้ :... | head -c4

เอาท์พุท (4 ตัวอักษร):

~~~~

หากต้องการดูผลลัพธ์ในรูปแบบ 8 บิตให้ไพพ์ลงในxxd(หรือของอื่น ๆ1 และ 0 ของ byte dump *):
เช่น b=10000000และไปที่:... | head -c4 | xxd -b

0000000: 10000000 10000000 10000000 10000000                    ....

1
คุณหมายถึงการเขียนo=$(printf ...)สำหรับบรรทัดที่สอง?
jwodder

1
@jwodder: ไม่บรรทัดที่สองถูกต้องตามที่แสดง printfตัวเลือกที่-vเป็นสาเหตุที่ทำให้การส่งออก Tthe การตั้งโดยตรงตัวแปรชื่อทันทีหลังจากนั้น ในกรณีนี้ชื่อของตัวแปรคือo(สำหรับฐานแปด ) - โปรดทราบว่า-vตัวเลือกนี้ใช้กับเวอร์ชันshell-builtinของ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'สำหรับเรื่องที่
kojiro

3
@kojiro: นั่นจะล้มเหลวถ้าคุณลองyesกระแส\nตัวอักษร อีกทางเลือกหนึ่งที่จัดการ\nคือ: yes '' | tr '\n' "$c"- ซึ่ง$cสามารถใช้อักขระ ASCII แบบเต็มรูปแบบได้
Peter.O

1
@ Peter.O yes 1 | tr -d $'\n'ผมไม่แน่ใจว่าวิธีการที่คุณตีความความคิดเห็นของฉันเพื่ออะไรหมายถึงอื่นที่ไม่ใช่ตัวอักษรแสดงออกคงที่ ฉันคิดว่าคุณสามารถใช้เชลล์ที่ไม่ได้ใช้$''แบ็กสแลชทรีทเม้นต์หรือคุณอาจลองหาโลแคลที่มีการเปลี่ยนแปลงtr -d $'\n'แต่ฉันยังไม่พบมัน
kojiro

@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 ()เพื่อ 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 ()ทำให้มันสามารถดึงไฟล์ descriptor ที่เกี่ยวข้องกับ / dev / zero จากนั้นเราจะดำเนินการกับแฮคเกอร์ในฟังก์ชั่น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 / ศูนย์ค้นหา / dev / capbee และปล่อย / dev / ศูนย์เพียงอย่างเดียว // dev / zero จะไม่เหมือนกันกับ / dev / zero
Robert Jacobs

1
@RobertJacobs แน่นอน เราสามารถสร้าง symlink / dev / 0x01, / dev / 0x02, / dev / 0x03, ... to / dev / zero และแยกชื่อไฟล์เพื่อกำหนด bitmask ที่จะใช้
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 'ขณะที่:; ทำเสียงสะท้อน -n "\ 1"; เสร็จสิ้น '| pv -a> / dev / null
[225KiB / s]
$ bash -c 'ขณะที่:; ทำ 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 ของฉันperlให้ผลตอบแทน 2.13GiB ในขณะที่< /dev/zeroให้ผลผลิต 8.73GiB สิ่งใดที่มีผลต่อประสิทธิภาพการทำงาน
cuonglm

@cuonglm ใช่ฉันเห็นความแตกต่างระหว่างระบบ แต่perlก็เร็วกว่าโซลูชั่นอื่น ๆ เสมอ ฉันได้ปริมาณงานเท่ากันกับโปรแกรม C ที่คอมไพล์แล้ว เกณฑ์มาตรฐานนั้นมีมากพอ ๆ กับแอปพลิเคชั่นเหมือนกับตัวกำหนดตารางเวลาของระบบที่นี่ สิ่งที่ทำให้แตกต่างที่สุดคือขนาดของบัฟเฟอร์ที่เขียน
Stéphane Chazelas

@cuonglm ท่อช้าลงด้วย ฉันคิดว่าcat /dev/zero| pv -a >/dev/nullจะให้คุณประมาณ 2 GiB ต่อวินาทีเช่นกัน (ในระบบของฉันในขณะที่< /dev/zero) ให้ฉันประมาณ 6GiBps
PSkocik

@ StéphaneChazelasฉันขอถามระบบของคุณได้ไหมStéphane Chazelas? ผลลัพธ์ของฉันค่อนข้างแตกต่างกัน (ฉันจะได้รับประมาณ 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/Linuxใช้ Intel 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.80GHz เคอร์เนลที่ใหม่กว่านั้นดูเหมือนจะสร้างความแตกต่าง (ยกเว้นว่ามันจะเป็น perl ที่ใหม่กว่า: v5.20.2)
Stéphane Chazelas

7

มันไม่มีประโยชน์ที่จะลองแล้ว bitmask / xor zero bytes ใช่ไหม? การไบต์และxoring กับศูนย์เป็น no-op

เพียงสร้างลูปที่ให้ไบต์ที่คุณต้องการและวางไว้ข้างหลังไพพ์หรือไพพ์ที่มีชื่อ มันจะทำงานเหมือนกับอุปกรณ์ตัวอักษร (จะไม่เสียรอบ 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)


ตอนแรกฉันพยายามใช้ putchar ใน C แต่มันช้า
PSkocik

จากความอยากรู้ว่าทำไมargc == 1+1แทนagrc == 2?
Reinstate Monica - ไม่ใช่

@iamnotmaynard เพื่อเตือนตัวเองว่ามันเป็น 1 สำหรับการปฏิบัติการบรรทัดคำสั่งบวก 1 อาร์กิวเมนต์ :-D
PSkocik

อา นั่นคือการเดาของฉัน แต่ต้องการให้แน่ใจว่าไม่มีเหตุผลที่เป็นความลับ
Reinstate Monica - notmaynard

"การใช้ไบต์และ xoring ด้วยศูนย์คือไม่มีการ op" สิ่งนี้ไม่เป็นความจริง: 0 XOR X == X.
jacwah

5

อ่านค่าศูนย์แปลแต่ละศูนย์ให้เป็นรูปแบบของคุณ!

เราอ่านศูนย์ไบต์ออกมา/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เพียงสี่เท่าในขณะที่มันสามารถใช้งานบัฟเฟอร์ 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 / ศูนย์และเพียงแค่รวบรวม / dev / หนึ่ง / dev / สอง, .. / dev / fourtytwo .. และอื่น ๆ บนอุปกรณ์

ในกรณีส่วนใหญ่ควรสร้างข้อมูลโดยตรงที่ต้องการได้ดีกว่าดังนั้นภายในโปรแกรม / สคริปต์เป็นค่าคงที่ ด้วยข้อมูลที่ผู้คนมากมายสามารถช่วยคุณได้ดียิ่งขึ้น


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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.