Làm cách nào tôi có thể đặt mặt nạ bit trên / dev / zero để tôi có thể nhận được các byte khác 0?


20

Làm cách nào tôi có thể đặt mặt nạ bit /dev/zerođể tôi có thể có nguồn không chỉ cho 0x00 mà còn cho bất kỳ byte nào trong khoảng từ 0x01 đến 0xFF?


8
Tại sao bạn hỏi Vui lòng chỉnh sửa câu hỏi để thúc đẩy nó.
Basile Starynkevitch

1
Bạn có thể sử dụng câu trả lời này làm tài liệu tham khảo: stackoverflow.com/questions/12634503/how-to-use-xor-in-bash
Romeo Ninov

Tôi đã đưa ra một câu trả lời cho câu hỏi này, nhưng đọc lại tôi nghĩ rằng tôi đã hiểu sai nó. Bạn có muốn dịch từng 0x00giá trị cụ thể hoặc thành một giá trị ngẫu nhiên trong 0x00-0xFFphạm vi không?
kos

1
@kos mỗi giá trị cụ thể như 444444...không phải là một giá trị ngẫu nhiên
Eduard Florinescu

Câu trả lời:


18

Đoạn bashmã sau được thiết lập để hoạt động với byte được biểu diễn dưới dạng nhị phân . Tuy nhiên bạn có thể dễ dàng thay đổi nó để xử lý ocatal , số thập phân hoặc hex bằng cách đơn giản thay đổi radix r giá trị của 2 để 8, 10hoặc 16tương ứng và thiết lập b=cho phù hợp.

r=2; b=01111110
printf -vo '\\%o' "$(($r#$b))"; </dev/zero tr '\0' "$o"

EDIT - Nó xử lý toàn bộ phạm vi của các giá trị byte: hex 00 - FF (khi tôi viết 00-7F bên dưới, tôi chỉ xem xét các ký tự UTF-8 byte đơn).

Ví dụ: nếu bạn chỉ muốn 4 byte (các ký tự trong phạm vi hex 00-7F chỉ dành cho UTF-8 'ASCII) , bạn có thể đặt nó vào đầu :... | head -c4

Đầu ra (4 ký tự):

~~~~

Để xem đầu ra ở định dạng 8 bit, hãy đưa nó vào xxd(hoặc bất kỳ kết xuất byte 1 và 0 nào khác *):
vd. b=10000000và đường ống đến:... | head -c4 | xxd -b

0000000: 10000000 10000000 10000000 10000000                    ....

1
Ý của bạn là viết o=$(printf ...)cho dòng thứ hai?
jwodder

1
@jwodder: Không, dòng thứ hai đúng như hình. Các printf lựa chọn -vgây tthe đầu ra trực tiếp thiết lập các biến có tên ngay sau khi nó; trong trường hợp này, tên của biến đó là o(cho bát phân ) - lưu ý rằng -vtùy chọn áp dụng cho phiên bản shell-dựng của printf(không phải cho phiên bản / usr / bin / printf )
Peter.O

2
@jwodder Ngoài ra, nói chung, -vtùy chọn đảm bảo biến được đặt thành chính xác những gì bạn đã chỉ định. $(...)biến đổi đầu ra đầu tiên. Đó là lý do tại sao o=$(printf '\n')sẽ không có hiệu quả bạn có thể mong đợi, trong khi printf -vo '\n'đó. (Không thành vấn đề ở đây, vì đầu ra ở đây ở dạng không bị ảnh hưởng bởi một phép biến đổi như vậy, nhưng nếu bạn không biết về -vtùy chọn này, thì điều này có thể hữu ích để biết.)
hvd

18

Bạn không thể dễ dàng làm điều đó.

Bạn có thể xem xét việc viết mô-đun hạt nhân của riêng bạn cung cấp một thiết bị như vậy. Tôi không khuyên bạn nên điều đó.

Bạn có thể viết một chương trình C nhỏ xíu viết một luồng vô hạn có cùng byte trên một số ống (hoặc trên stdout) hoặc FIFO.

Bạn có thể sử dụng tr (1) để đọc /dev/zerovà dịch mỗi 0 byte sang đôi khi khác.

Bạn có thể sử dụng có lẽ có (1) , ít nhất là nếu bạn có đủ khả năng để có những dòng mới (hoặc nếu không thì đưa nó vào tr -d '\n'...)


10
Hoặc sử dụng yes 1 | tr -d $'\n'cho vấn đề đó.
kojiro

3
@kojiro: điều đó sẽ thất bại nếu bạn cố gắng tạo ra yesmột dòng \nký tự. Một thay thế xử lý \nlà: yes '' | tr '\n' "$c"- nơi $ccó thể là bất kỳ char nào trong phạm vi đầy đủ các ký tự ASCII.
Peter.O

1
@ Peter.O Tôi không chắc làm thế nào bạn diễn giải bình luận của tôi có nghĩa là bất cứ điều gì khác ngoài biểu thức tĩnh, nghĩa đen yes 1 | tr -d $'\n'. Tôi cho rằng bạn có thể sử dụng một trình bao không thực hiện $''xử lý dấu gạch chéo ngược hoặc bạn có thể cố gắng tìm một địa điểm thay đổi tr -d $'\n', nhưng tôi chưa tìm thấy nó.
kojiro

@kojiro: Bạn yes 1 | tr -d $'\n'sẽ khá vui vẻ in một luồng 1ký tự và hầu hết mọi giá trị byte đơn khác, nhưng nó không thể in một luồng \nký tự. OP muốn có thể xử lý tất cả các giá trị byte "trong khoảng từ 0x01 đến 0xFF"
Peter.O

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

13

Chà, nếu bạn thực sự muốn đạt được điều này, bạn có thể sử dụng móc LD_PRELOAD . Ý tưởng cơ bản là viết lại một hàm từ thư viện C và sử dụng nó thay vì hàm bình thường.

Dưới đây là một ví dụ đơn giản trong đó chúng ta ghi đè hàm read () thành XOR bộ đệm đầu ra với 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);    
}

Một triển khai ngây thơ sẽ XOR 0x42 trên mỗi tệp chúng ta đọc, điều này sẽ có hậu quả không mong muốn. Để giải quyết vấn đề này, tôi cũng đã nối hàm open () , làm cho nó tìm nạp mô tả tệp được liên kết với / dev / zero. Sau đó, chúng tôi chỉ thực hiện XOR trong hàm read () nếu fd == dev_zero_fd.

Sử dụng:

$ gcc hook.c -ldl -shared -o hook.so
$ LD_PRELOAD=$(pwd)/hook.so bash #this spawns a hooked shell
$ cat /dev/zero
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

3
Với việc triển khai của bạn, bạn có thể có một liên kết tượng trưng từ / dev / capbee đến / dev / zero, tìm kiếm / dev / capbee và để lại / dev / zero một mình. // dev / zero sẽ không giống như / dev / zero.
Robert Jacobs

1
@RobertJacobs Thật vậy. Chúng tôi thậm chí có thể tạo symlink / dev / 0x01, / dev / 0x02, / dev / 0x03, ... đến / dev / zero và phân tích tên tệp để xác định bitmask để áp dụng.
yoann

11

Về tốc độ, nhanh nhất tôi tìm thấy là:

$ PERLIO=:unix perl -e '$s="\1" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]

Để so sánh:

$ 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 :; làm tiếng vang -n "\ 1"; xong '| pv -a> / dev / null
[225Ki / giây]
$ bash -c 'while :; làm tiếng vang -ne "\ 1"; xong '| pv -a> / dev / null
[180Ki / giây]

$ < /dev/zero pv -a > /dev/null
[5.56GiB/s]
$ cat /dev/zero | pv -a > /dev/null
[2.82GiB/s]

Trong Debian của tôi, perlmang lại 2,13GiB, trong khi < /dev/zeromang lại 8,73GiB. Điều gì có thể ảnh hưởng đến hiệu suất?
cuonglm

@cuonglm, vâng, tôi thấy một số biến thể giữa các hệ thống, nhưng perlluôn nhanh hơn các giải pháp khác. Tôi nhận được thông lượng tương tự như với chương trình C được biên dịch tương đương. Điểm chuẩn là nhiều trên ứng dụng như trên lịch trình của hệ thống ở đây. Điều làm cho sự khác biệt nhất là kích thước của bộ đệm được viết.
Stéphane Chazelas

@cuonglm Ống làm nó chậm quá. Tôi nghĩ rằng cat /dev/zero| pv -a >/dev/nullcũng sẽ cung cấp cho bạn khoảng 2 GiB mỗi giây (trong hệ thống của tôi, trong khi đó < /dev/zero) mang lại cho tôi khoảng 6GiBps.
PSkocik

@ StéphaneChazelas Tôi có thể hỏi bạn đang sử dụng hệ thống nào không, Stéphane Chazelas? Các kết quả trên tôi khá khác nhau (tôi có thể nhận được khoảng 2.1GiB từ phiên bản perl). Tôi đang ở trên 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.80GHz. Hạt nhân mới hơn dường như tạo ra sự khác biệt (trừ khi đó là perl mới hơn: v5.20.2)
Stéphane Chazelas

7

Thật là vô nghĩa khi thử và bitmask / xor zero byte, phải không? Lấy một byte và lấy xornó bằng 0 là không có.

Chỉ cần tạo một vòng lặp cung cấp cho bạn các byte bạn muốn và đặt nó phía sau một đường ống hoặc đường ống có tên. Nó sẽ hoạt động khá giống với một thiết bị nhân vật (sẽ không lãng phí chu kỳ CPU khi không hoạt động):

mkfifo pipe
while : ; do echo -n "a"; done > pipe &

Và nếu bạn muốn siêu tối ưu hóa nó, bạn có thể sử dụng mã C bên dưới:

#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)); 
  }
}

biên dịch và chạy

$ CFLAGS=-O3 make loop
./loop "$the_byte_you_want" > pipe

Kiểm tra hiệu suất:

./loop 1 | pv -a >/dev/null 

2.1GB / s trên máy của tôi (thậm chí nhanh hơn một chút cat /dev/zero | pv -a >/dev/null)


Ban đầu tôi đã thử sử dụng putar trong C, nhưng nó chậm.
PSkocik

Vì tò mò, tại sao argc == 1+1thay vì agrc == 2?
Tái lập lại Monica iamnotmaynard

@iamnotmaynard Để tự nhắc nhở bản thân rằng đó là 1 cho dòng lệnh thực thi cộng với 1 đối số. :-D
PSkocik

À. Đó là dự đoán của tôi, nhưng muốn chắc chắn rằng không có lý do bí mật nào.
Tái lập lại Monica iamnotmaynard

"Lấy một byte và xé nó bằng 0 là không có." Điều này không đúng : 0 XOR X == X.
jacwah

5

Đọc số không, dịch từng số 0 vào mẫu của bạn!

Chúng tôi đọc các byte không trong số đó /dev/zerovà sử dụng trđể áp dụng mặt nạ bit cho mỗi byte bằng cách dịch từng byte 0:

$ </dev/zero tr '\000' '\176' | head -c 10
~~~~~~~~~~$

Octal 176 là mã ascii của ~, vì vậy chúng tôi nhận được 10 ~. (Ở $cuối đầu ra cho biết trong vỏ của tôi rằng không có đầu cuối dòng - nó có thể trông khác với bạn)

Vì vậy, hãy tạo 0xFFbyte: Hex 0xFFlà bát phân 0377. Số 0 đứng đầu được để lại cho trdòng lệnh; Cuối cùng, hexdumpđược sử dụng để làm cho đầu ra có thể đọc được.

$ </dev/zero tr '\000' '\377' | head -c 10 | hexdump
0000000 ffff ffff ffff ffff ffff               
000000a

Bạn cần sử dụng mã bát phân của các ký tự ở đây, thay vì thập lục phân. Vì vậy, đó là phạm vi từ \000đến bát phân \377(giống như 0xFF).
Sử dụng ascii -xascii -ođể có được một bảng các ký tự có số chỉ số thập lục phân hoặc bát phân.
(Đối với một bảng có thập phân và thập lục phân, chỉ ascii).

Khá nhanh

Nó chạy khá nhanh, so với việc chỉ sử dụng các số không: cat /dev/zerochỉ nhanh gấp bốn lần, trong khi nó có thể sử dụng bộ đệm IO hoàn hảo, điều này trkhông thể.

$ </dev/zero tr '\000' '\176' | pv -a >/dev/null
[ 913MB/s]

$ </dev/zero cat | pv -a >/dev/null        
[4.37GB/s]

3

Phụ thuộc vào những gì bạn muốn làm với dữ liệu và mức độ linh hoạt bạn muốn sử dụng nó.

Trường hợp xấu nhất nếu bạn cần tốc độ, bạn có thể làm tương tự như / dev / zero và chỉ cần biên dịch / dev / one, / dev / hai, .. / dev / Fourtytwo .. và trên các thiết bị.

Trong hầu hết các trường hợp, tốt hơn là tạo dữ liệu trực tiếp ở nơi cần thiết, vì vậy bên trong một chương trình / tập lệnh là một hằng số. Với nhiều thông tin mọi người có thể giúp bạn tốt hơn.


1

Vòng lặp in Infinte

Reeplace \u00với byte bạn muốn.

while true ; do printf "\u00" ; done | yourapp

Mã C ++:

#include<cstdio>

int main(){
 char out=Byte;
 while(true)
 fwrite(&out,sizeof(out),1,stdout);
}

Biên dịch: reeplace Bytevới giá trị bạn muốn.

g++ -O3 -o bin file.cpp -D Byte=0x01

Sử dụng

./bin | yourapp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.