2010-04-30 34 views
13

Tôi có một tệp có dữ liệu nhị phân và tôi cần phải thay thế một vài byte ở một vị trí nhất định. Tôi đã đưa ra những điều sau đây để chỉ đạo bash để bù đắp và chỉ cho tôi mà nó tìm thấy nơi tôi muốn:sử dụng bash: ghi bit đại diện của số nguyên vào tập tin

dd bs=1 if=file iseek=24 conv=block cbs=2 | hexdump 

Bây giờ, để sử dụng "tập tin" như đầu ra:

echo anInteger | dd bs=1 of=hextest.txt oseek=24 conv=block cbs=2 

Điều này dường như làm việc tốt, tôi có thể xem lại những thay đổi được thực hiện trong một trình soạn thảo hex. Vấn đề là, "anInteger" sẽ được viết như là biểu diễn ASCII của số nguyên đó (có ý nghĩa) nhưng tôi cần phải viết biểu diễn nhị phân.

Tôi muốn sử dụng bash cho điều này và tập lệnh sẽ chạy trên càng nhiều hệ thống càng tốt (Tôi không biết liệu hệ thống đích sẽ có python hay bất kỳ cài đặt nào).

Làm cách nào để yêu cầu lệnh chuyển đổi đầu vào thành nhị phân (có thể từ hex)?

+0

Bạn có thể muốn sử dụng xdelta cho điều này - nó đủ phổ biến mà nó có thể là 'phổ quát' cho bạn. – MikeyB

+0

Không chắc chắn ý bạn là gì bởi "xdelta". Không có lệnh như vậy trên vỏ của tôi ... –

Trả lời

10

Bạn có thể sử dụng tiếng vang để phát ra các byte cụ thể bằng hex hoặc bát phân. Ví dụ:

echo -n -e \\x30 

sẽ in ascii 0 (0x30)

(-n loại bỏ trailing newline)

+0

Điều này dường như hoạt động. Tôi sẽ cố gắng tìm ra và đăng kết quả của mình. –

+3

echo là đáng lo ngại không thể di chuyển - ví dụ trên, một số triển khai sẽ chỉ in '-e \ x30', mà không phải là những gì bạn muốn ở tất cả. –

+0

Lạ lùng, không nghĩ như vậy. May mắn là kịch bản đã chạy mà không có vấn đề gì. –

0

Nếu bạn sẵn sàng dựa vào bc (đó là khá phổ biến)

echo -e "ibase=16\n obase=2 \n A1" | bc -q 

có thể giúp đỡ.

+0

Tôi đã thử nó. Mã của bạn sẽ trả về một tệp nhị phân sẽ được ghi vào tệp dưới dạng biểu diễn ASCII của nhị phân đó. Nice nghĩ mặc dù, cảm ơn. –

0

Bạn có thể đặt đầu vào mong muốn vào một tệp và sử dụng tùy chọn "if =" để dd để chèn chính xác đầu vào bạn muốn.

+0

Tôi nghĩ về điều đó nhưng tôi không muốn sử dụng một tệp phụ cho 4 byte. –

13

printf là xách tay hơn echo. Hàm này lấy một số nguyên thập phân và xuất ra một byte với giá trị đó:

echobyte() { 
    if (($1 >= 0 && $1 <= 255)) 
    then 
     printf "\\x$(printf "%x" $1)" 
    else 
     printf "Invalid value\n" >&2 
     return 1 
    fi 
} 

$ echobyte 97 
a 
$ for i in {0..15}; do echobyte $i; done | hd 
00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................| 
00000010 
+0

Ngọt ngào! Nhưng như bạn có thể thấy trong câu trả lời của tôi dưới đây, điều đó có lẽ sẽ là quá mức cần thiết. Tuy nhiên, tốt đẹp để biết. –

+0

Nếu bạn biết trước số nguyên, bạn có thể đơn giản hóa điều này một chút, ví dụ: 'printf" \ x30 "' –

+0

@Gordon: Đúng là xem câu trả lời của [OP] (http://stackoverflow.com/questions/2746707/using-bash-write-bit-representation-of-integer-to-file/ 2747396 # 2747396). Tuy nhiên, toàn bộ mục đích của chức năng này là tính linh hoạt. –

4

Làm việc giống như một điều trị. Tôi đã sử dụng đoạn mã sau để thay thế 4 byte tại byte 24 ở cuối nhỏ với hai số nguyên (1032 và 1920). Mã không cắt bớt tệp.

echo -e \\x08\\x04\\x80\\x07 | dd of=<file> obs=1 oseek=24 conv=block,notrunc cbs=4 

Xin cảm ơn một lần nữa.

5

xxd là cách tốt hơn. xxd -r infile outfile sẽ mất ascii hex-giá trị trong infile vá outfile, và bạn có thể xác định vị trí cụ thể trong infile của thành viên này: 1FE:55AA

0

Tôi có một chức năng để làm điều này:

# number representation from 0 to 255 (one char long) 
function chr() { printf "\\$(printf '%03o' "$1")" ; return 0 ; } 
# from 0 to 65535 (two char long) 
function word_litleendian() { chr $(($1/256)) ; chr $(($1 % 256)) ; return 0 ; } 
function word_bigendian() { chr $(($1 % 256)) ; chr $(($1/256)) ; return 0 ; } 
# from 0 to 4294967295 (four char long) 
function dword_litleendian() { word_lilteendian $(($1/65536)) ; word_litleendian $(($1 % 65536)) ; return 0 ; } 
function dword_bigendian() { word_bigendian $(($1/65536)) ; word_bigendian $(($1 % 65536)) ; return 0 ; } 

Bạn có thể sử dụng đường ống hoặc chuyển hướng để nắm bắt kết quả.

0

Với bash, "printf" có tùy chọn "-v" và tất cả trình bao đều có toán tử logic.

Vì vậy, đây là hình thức đơn giản hơn trong bash:

int2bin() { 
    local i=$1 
    local f 
    printf -v f '\\x%02x\\x%02x\\x%02x\\x%02x' $((i&255)) $((i >> 8 & 255)) $((i >> 16 & 255)) $((i >> 24 & 255)) 
    printf "$f" 
} 
0

Trong trường hợp của tôi, tôi cần phải đi từ một đối số số thập phân với 16-bit giá trị về cuối lớn unsigned thực tế. Đây có lẽ không phải là cách hiệu quả nhất, nhưng nó hoạt động:

# $1 is whatever number (0 to 65535) the caller specifies 
DECVAL=$1 
HEXSTR=`printf "%04x" "$DECVAL"` 
BYTEONE=`echo -n "$HEXSTR" | cut -c 1-2` 
BYTETWO=`echo -n "$HEXSTR" | cut -c 3-4` 
echo -ne "\x$BYTEONE\x$BYTETWO" | dd of="$FILENAME" bs=1 seek=$((0xdeadbeef)) conv=notrunc 
Các vấn đề liên quan