Sıfır dışında bayt alabilmem için / dev / zero üzerine nasıl biraz maske koyabilirim?


20

/dev/zeroSadece 0x00 için değil, aynı zamanda 0x01 ve 0xFF arasındaki herhangi bir bayt için de bir kaynağa sahip olabilmem için nasıl bir bit maskesi takabilirim?


8
Neden soruyorsun? Motive etmek için lütfen soruyu düzenleyin.
Basile Starynkevitch

1
Bu yanıtı referans olarak kullanabilirsiniz: stackoverflow.com/questions/12634503/how-to-use-xor-in-bash
Romeo Ninov 10:15

Bu soruya bir cevap verdim, ama tekrar okuduğumu düşünüyorum. Her 0x00birini belirli bir değere 0x00-0xFFmi yoksa aralıktaki rastgele bir değere mi çevirmek istiyorsunuz ?
kos

1
@kos 444444...rastgele değil gibi belirli bir değere
Eduard Florinescu

Yanıtlar:


18

Aşağıdaki bashkod ikili olarak temsil edilen bayt ile çalışacak şekilde ayarlanmıştır . Ancak kolayca işlemek için bunu değiştirebilirsiniz ocatal , ondalık veya onaltılık basitçe değiştirerek radix r değerini 2 etmek 8, 10ya da 16sırasıyla ve ayar b=buna göre.

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

DÜZENLEME - Tüm bayt değerleri aralığını işler : hex 00 - FF (aşağıda 00-7F yazdığımda, yalnızca tek bayt UTF-8 karakterleri düşünüyordum).

Örneğin, yalnızca 4 bayt istiyorsanız (UTF-8 'ASCII' okunur altıgen 00-7F aralığında karakter) , içine boru bunu yapabilirsiniz kafa :... | head -c4

Çıktı (4 karakter):

~~~~

Çıkışı 8 bit biçiminde görmek için xxd(veya diğer 1'ler ve 0'ların bayt dökümü *) içine boru bağlayın:
örn. b=10000000ve boru tesisatı:... | head -c4 | xxd -b

0000000: 10000000 10000000 10000000 10000000                    ....

1
o=$(printf ...)İkinci satır için mi yazmak istediniz ?
jwodder

1
@jwodder: Hayır, ikinci satır gösterildiği gibi doğrudur. Printf seçeneği -vdoğrudan ondan sonra hemen adlandırılmış değişkeni ayarlamak için tthe çıktısına sebep; bu durumda değişkenin adı o( sekizli için ) - -vseçeneğin kabuk yerleşik sürümüne printf( / usr / bin / printf sürümüne değil)
Peter.O

2
@jwodder Ayrıca, -vseçenek genel olarak değişkenin tam olarak belirttiğiniz şekilde ayarlanmasını sağlar . $(...)önce çıkışı dönüştürür. Bu yüzden o=$(printf '\n')beklediğiniz etkiye sahip olmayacaksınız printf -vo '\n'. (Burada önemli değil, çünkü buradaki çıktı böyle bir dönüşümden etkilenmeyen bir formda, ancak -vseçeneğin farkında değilseniz, bunu bilmek yararlı olabilir.)
hvd

18

Bunu kolayca yapamazsın.

Böyle bir cihaz sağlayan kendi çekirdek modülünüzü yazmayı düşünebilirsiniz. Bunu tavsiye etmiyorum.

Bazı pipo (veya üzerinde stdout) veya FIFO üzerine aynı baytlardan oluşan sonsuz bir akım yazarak küçük bir C programı yazabilirsiniz .

Sen kullanabilirsiniz tr (1) okuma /dev/zerove başka seyler her 0 bayt çevirmek.

Belki de evet (1) kullanabilirsiniz , en azından yeni satırlara sahip olmayı göze alabiliyorsanız (ya da başka bir yere tr -d '\n'...)


10
Veya yes 1 | tr -d $'\n'bu konuda kullanın .
kojiro

3
@kojiro: karakter yesakışını denerseniz bu başarısız olur \n. İşleyen bir alternatif \n: yes '' | tr '\n' "$c"- $ctüm ASCII karakterlerinin herhangi bir karakteri olabilir.
Peter.O

1
@ Peter.O Yorumumu gerçek, statik ifadeden başka bir anlamla nasıl yorumladığınızdan emin değilim yes 1 | tr -d $'\n'. Sanırım $''ters eğik çizgi tedavisini yapmayan bir kabuk kullanabilirsiniz ya da değişen bir yerel ayar bulmaya çalışabilirsiniz tr -d $'\n', ama henüz bulamadım.
kojiro

@kojiro: yes 1 | tr -d $'\n'Bir 1karakter akışını ve neredeyse her bir tek baytlık değeri oldukça mutlu bir şekilde yazdırabilirsiniz , ancak bir \nkarakter akışını yazdıramaz . OP, "0x01 ve 0xFF arasındaki"
Peter.O

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

13

Eğer buysa, tam anlamıyla bunu başarmak istiyorum, bir kullanabilirsiniz LD_PRELOAD kanca . Temel fikir, bir işlevi C kütüphanesinden yeniden yazmak ve normal işlev yerine kullanmaktır.

Burada, 0x42 ile çıktı arabelleğini XOR yapmak için read () işlevini geçersiz kıldığımız basit bir örnek .

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

Saf bir uygulama, okuduğumuz her dosyada XOR 0x42 olur ve bu da istenmeyen sonuçlara yol açar. Bu sorunu çözmek için, open () işlevini de bağladım ve / dev / zero ile ilişkili dosya tanımlayıcısını getirdim . Ardından, XOR komutunu yalnızca read () işlevimizde yaparız fd == dev_zero_fd.

Kullanımı:

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

3
Uygulamanız göz önüne alındığında, / dev / capbee ile / dev / zero arasında sembolik bir bağlantınız olabilir, / dev / capbee için arama yapın ve / dev / zero komutunu yalnız bırakın. // dev / zero, / dev / zero ile aynı şekilde çalışmayacak.
Robert Jacobs

1
@RobertJacobs Gerçekten. Hatta / dev / zero için semboller / dev / 0x01, / dev / 0x02, / dev / 0x03, ... üretebilir ve uygulanacak bit maskesini belirlemek için dosya adını ayrıştırabiliriz.
yoann

11

Hız açısından, bulduğum en hızlı şey:

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

Karşılaştırma için:

$ 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 'ise:; echo -n "\ 1" yapın; bitti '| pv -a> / dev / null
[225 KB / sn]
$ bash -c 'ise:; echo -ne "\ 1" yapın; bitti '| pv -a> / dev / null
[180 KB / sn]

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

Debian'ımda perl2.13GiB, < /dev/zeroverim 8.73GiB veriliyor. Performansı ne etkileyebilir?
cuonglm

@cuonglm, evet, sistemler arasında bazı farklılıklar görüyorum, ancak perlsürekli olarak diğer çözümlerden daha hızlı. Eşdeğer derlenmiş C programı ile aynı verimi alıyorum. Kıyaslama, buradaki sistem zamanlayıcısında olduğu kadar uygulamada da geçerlidir. En farklı kılan şey, yazılan arabelleklerin boyutudur.
Stéphane Chazelas

@cuonglm Boru da yavaşlatır. Sanırım cat /dev/zero| pv -a >/dev/nullsize saniyede yaklaşık 2 GiB verecek (sistemimde ise < /dev/zero) 6GiBps civarında.
PSkocik

@ StéphaneChazelas Hangi sistemde olduğunuzu sorabilir miyim, Stéphane Chazelas? Madendeki sonuçlar oldukça farklı (perl versiyonundan yaklaşık 2.1GiB alabilirim). Hattayım 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 Core i5 içeriden.
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. Yeni çekirdek bir fark yaratıyor gibi görünüyor (yeni perl olmadığı sürece: v5.20.2)
Stéphane Chazelas

7

Denemek ve sıfır bayt / x veya sıfır bayt denemek anlamsız, değil mi? Bayt almak ve xorsıfırla doldurmak bir işlem değildir.

İstediğiniz baytları veren bir döngü oluşturun ve bir piponun veya adlandırılmış bir borunun arkasına koyun. Bir karakter cihazıyla hemen hemen aynı davranacaktır (boşta iken CPU döngülerini boşa harcamaz):

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

Ve süper optimize etmek istiyorsanız, aşağıdaki C kodunu kullanabilirsiniz:

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

derle ve çalıştır

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

Performans testi:

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

Makinemde 2,1GB / s (biraz daha hızlı cat /dev/zero | pv -a >/dev/null)


Başlangıçta C'de putchar kullanmayı denedim, ama yavaştı.
PSkocik

Meraktan, neden argc == 1+1yerine agrc == 2?
Monica'yı eski durumuna getirme - notmaynard

@iamnotmaynard Komut satırı yürütülebilir artı 1 argümanı için 1 olduğunu kendime hatırlatmak isterim. :-D
PSkocik

Ah. Bu benim tahminimdi, ama gizli bir neden olmadığından emin olmak istedim.
Monica'yı eski durumuna getirme - notmaynard

"Bir bayt almak ve sıfırla xoring yapmak hiç de kolay değildir." Bu doğru değildir: 0 XOR X == X.
jacwah

5

Sıfırları okuyun, her sıfırı deseninize çevirin!

Sıfır baytı okur /dev/zerove trher bir sıfır baytı çevirerek her bir bayta bit maskesi uygulamak için kullanırız :

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

Octal 176 ascii kodudur ~, bu yüzden 10 elde ederiz ~. ( $Çıktının sonunda kabuğumda satır sonu olmadığını gösterir - sizin için farklı görünebilir)

Şimdi 0xFFbayt oluşturalım : Hex 0xFFsekizli 0377. Baştaki sıfır trkomut satırı için dışarıda bırakılır ; Sonunda, hexdumpçıkışı okunabilir hale getirmek için kullanılır.

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

Onaltılı yerine, karakterlerin sekizlik kodlarını kullanmanız gerekir. Yani gelen aralık var \000sekizlik biçime \377(aynı 0xFF). Onaltılık veya sekizli dizin numaralarına sahip karakterlerin bir tablosunu almak için ve
tuşlarını kullanın . (Ondalık ve onaltılık bir tablo için, sadece ).ascii -xascii -o
ascii

Oldukça hızlı

Sadece sıfırları kullanmaya kıyasla oldukça hızlı çalışır: cat /dev/zerosadece dört kat daha hızlıdır, IO tamponlamasını mükemmel bir şekilde kullanabilir tr.

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

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

3

Verilerle ne yapmak istediğinize ve bunları ne kadar esnek kullanmak istediğinize bağlıdır.

En kötü durumda hıza ihtiyacınız varsa, / dev / zero ile aynı şeyi yapabilir ve / dev / one, / dev / two, .. / dev / fourtytwo .. ve benzeri aygıtları derleyebilirsiniz.

Çoğu durumda, verileri doğrudan gerektiği yerde oluşturmak daha iyi olmalıdır, bu nedenle bir programın / komut dosyasının içinde sabit olarak. Daha fazla bilgi ile insanlar size daha iyi yardımcı olabilir.


1

Infinte printf döngüsü

İstediğiniz \u00bayt ile değiştirin.

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

C ++ kodu:

#include<cstdio>

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

Derleme: reeplace Byteistediğiniz değeri ile.

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

kullanım

./bin | yourapp

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.