Yanıtlar:
Kabuk yardımcı programlarına bağlı kalmak istiyorsanız, head
birkaç bayt ayıklamak ve od
baytı bir sayıya dönüştürmek için kullanabilirsiniz.
export LC_ALL=C # make sure we aren't in a multibyte locale
n=$(head -c 1 | od -An -t u1)
string=$(head -c $n)
Ancak, bu ikili veriler için çalışmaz . İki sorun var:
Komut ikamesi $(…)
şeritler nihai yeni satır komutu çıktısında. Oldukça kolay bir çözüm var: çıktının yeni satırdan başka bir karakterle sona erdiğinden emin olun, ardından bu karakteri soyun.
string=$(head -c $n; echo .); string=${string%.}
Bash, çoğu kabuk gibi, boş baytlarla uğraşmada kötüdür . Bash 4.1'den itibaren, boş baytlar komut değiştirme işleminin sonucundan çıkarılır. Çizgi 0.5.5 ve pdksh 5.2 aynı davranışa sahiptir ve ATT ksh ilk boş baytta okumayı durdurur. Genel olarak, kabuklar ve bunların yardımcı programları ikili dosyalarla uğraşmaya yönelik değildir. (Zsh istisnadır, boş baytları desteklemek için tasarlanmıştır.)
İkili verileriniz varsa, Perl veya Python gibi bir dile geçmek istersiniz.
<input_file perl -e '
read STDIN, $c, 1 or die $!; # read length byte
$n = read STDIN, $s, ord($c); # read data
die $! if !defined $n;
die "Input file too short" if ($n != ord($c));
# Process $s here
'
<input_file python -c '
import sys
n = ord(sys.stdin.read(1)) # read length byte
s = sys.stdin.read(n) # read data
if len(s) < n: raise ValueError("input file too short")
# Process s here
'
exec 3<binary.file # open the file for reading on file descriptor 3
IFS= #
read -N1 -u3 char # read 1 character into variable "char"
# to obtain the ordinal value of the char "char"
num=$(printf %s "$char" | od -An -vtu1 | sed 's/^[[:space:]]*//')
read -N$num -u3 str # read "num" chars
exec 3<&- # close fd 3
read -N
boş baytta durur, bu nedenle bu ikili verilerle çalışmak için uygun bir yol değildir. Genel olarak, zsh dışındaki mermiler boş değerlerle baş edemez.
Eğer kabuk ikili dosya ile başa çıkmak istiyorsanız, en iyi seçenek (sadece?) Hexdump aracı ile çalışmaktır .
hexdump -v -e '/1 "%u\n"' binary.file | while read c; do
echo $c
done
Yalnızca X baytını oku:
head -cX binary.file | hexdump -v -e '/1 "%u\n"' | while read c; do
echo $c
done
Uzunluğu okuyun (ve uzunluk olarak 0 ile çalışın) ve ardından bayt ondalık değeri olarak "dize":
len=$(head -c1 binary.file | hexdump -v -e '/1 "%u\n"')
if [ $len -gt 0 ]; then
tail -c+2 binary.file | head -c$len | hexdump -v -e '/1 "%u\n"' | while read c; do
echo $c
done
fi
GÜNCELLEME (geziyle birlikte): ... Bu soru / cevap (cevabım) arabayı kovalayan köpeği düşünmemi sağlıyor .. Bir gün, nihayet arabaya yetişiyor .. Tamam, yakaladı, ama o gerçekten onunla pek bir şey yapamaz ... Bu anser ipleri 'yakalar', ancak sonra boş bayt yerleştirmişlerse onlarla çok fazla şey yapamazsınız ... (böylece Gilles'in cevabına büyük bir +1 .. burada başka bir dil düzenlenmiş olabilir.)
dd
tüm verileri okur ... Kesinlikle sıfır olarak "uzunluk" olarak baulk olmaz ... ama verilerinizde herhangi bir yerde \ x00 varsa, nasıl işlediğiniz konusunda yaratıcı olmanız gerekir; dd
onunla herhangi bir sorun yoktur, ancak kabuk betiğinizde sorunlar olacaktır (ancak verilerle ne yapmak istediğinize bağlıdır) ... Aşağıdaki temelde her "veri dizesini" her strin arasında bir çizgi bölücüsü olan bir dosyaya çıkarır ...
btw: "Karakter" diyorsunuz ve "bayt" demek istediğinizi varsayalım ...
ancak "karakter" kelimesi UNICODE'un bu günlerinde belirsiz hale geldi, burada sadece 7 bitlik ASCII karakter kümesi karakter başına tek bir bayt kullanıyor ... Ve Unicode sisteminde bile, bayt sayıları karakterleri kodlama yöntemine bağlı olarak değişir , örn. UTF-8, UTF-16 vb.
İşte bir Metin "karakteri" ve bayt arasındaki farkı vurgulamak için basit bir komut dosyası.
STRING="௵"
echo "CHAR count is: ${#STRING}"
echo "BYTE count is: $(echo -n $STRING|wc -c)"
# CHAR count is: 1
# BYTE count is: 3 # UTF-8 ecnoded (on my system)
Senin uzunluğu ise karakter uzunluğunda 1 bayt ve bir işaret bayt uzunlukta , o zaman bu senaryo ... veri Unicode karakterleri içerse bile hile yapmak gerekir dd
yalnızca görür bayt bakılmaksızın herhangi yerel ayarı ...
Bu komut dosyası dd
ikili dosyayı okumak için kullanır ve "====" ayırıcısı ile ayrılmış dizeleri çıkarır ... Test verileri için sonraki komut dosyasına bakın
#
div="================================="; echo $div
((skip=0)) # read bytes at this offset
while ( true ) ; do
# Get the "length" byte
((count=1)) # count of bytes to read
dd if=binfile bs=1 skip=$skip count=$count of=datalen 2>/dev/null
(( $(<datalen wc -c) != count )) && { echo "INFO: End-Of-File" ; break ; }
strlen=$((0x$(<datalen xxd -ps))) # xxd is shipped as part of the 'vim-common' package
#
# Get the string
((count=strlen)) # count of bytes to read
((skip+=1)) # read bytes from and including this offset
dd if=binfile bs=1 skip=$skip count=$count of=dataline 2>/dev/null
ddgetct=$(<dataline wc -c)
(( ddgetct != count )) && { echo "ERROR: Line data length ($ddgetct) is not as expected ($count) at offset ($skip)." ; break ; }
echo -e "\n$div" >>dataline # add a newline for TEST PURPOSES ONLY...
cat dataline
#
((skip=skip+count)) # read bytes from and including this offset
done
#
echo
çıkış
Bu komut dosyası, satır başına 3 bayt önek içeren test verileri oluşturur ...
Önek, UTF-8 kodlu tek bir Unicode karakterdir ...
# build test data
# ===============
prefix="௵" # prefix all non-zero length strings will this obvious 3-byte marker.
prelen=$(echo -n $prefix|wc -c)
printf \\0 > binfile # force 1st string to be zero-length (to check zero-length logic)
( lmax=3 # line max ... the last on is set to 255-length (to check max-length logic)
for ((i=1;i<=$lmax;i++)) ; do # add prefixed random length lines
suflen=$(numrandom /0..$((255-prelen))/) # random length string (min of 3 bytes)
((i==lmax)) && ((suflen=255-prelen)) # make last line full length (255)
strlen=$((prelen+suflen))
printf \\$((($strlen/64)*100+$strlen%64/8*10+$strlen%8))"$prefix"
for ((j=0;j<suflen;j++)) ; do
byteval=$(numrandom /9,10,32..126/) # output only printabls ASCII characters
printf \\$((($byteval/64)*100+$byteval%64/8*10+$byteval%8))
done
# 'numrandom' is from package 'num-utils"
done
) >>binfile
#
/dev/urandom
Çoğu birleşimden rasgele bayt alabilirsiniz . Ve rastgele test verileri en iyi test verileri değildir, burada, sınır yerlerinde boş karakterler ve satırsonu gibi zor durumları ele aldığınızdan emin olmalısınız.