Tìm nạp các byte riêng lẻ từ tệp nhị phân vào một biến bằng bash


8

Tôi cần tạo một tập lệnh bash khá đơn giản để lấy từng byte một từ tệp nhị phân, gửi nó ra một cổng nối tiếp và sau đó đợi một byte quay trở lại trước khi tôi gửi cái tiếp theo. Điều này có hiệu quả đối với một lập trình viên EEPROM, nơi giải pháp không có giá trị sẽ không hoạt động.

Tôi hầu như bị mắc kẹt trong việc kéo các byte ra khỏi tệp thành một biến, ngoài ra tôi biết tôi có thể lặp lại các giá trị xuống cổng nối tiếp và đọc lại chúng bằng dd. (Có cách nào tốt hơn để làm điều đó không?)

Cảm ơn đã giúp đỡ!


byte trả về chắc chắn sẽ luôn luôn đến đơn? Như trong, bạn sẽ chỉ nhận được một byte cho mỗi byte được gửi?
mikeerv

Bạn có thể làm việc với các giá trị hex, như sử dụng lệnh xxd -psxxd -r -ps. Nó sẽ an toàn hơn.
LatinSuD

Bash IIRC không thể đối phó với byte rỗng, vì vậy không phù hợp để xử lý dữ liệu nhị phân. Hầu hết các shell không được thiết kế để xử lý dữ liệu nhị phân (zsh là một ngoại lệ). Đây có phải là một hệ thống nhúng? Nếu vậy làm thế nào hạn chế là bộ công cụ của bạn?
Gilles 'SO- ngừng trở thành ác quỷ'

Vâng, thiết bị ở đầu xa sẽ chuyển tiếp cùng một byte được gửi đi, sau khi thiết bị đã trải qua một chút xử lý ở đầu thiết bị.
Solitaireig666

Kịch bản này chỉ diễn ra trên một máy tính xách tay của Ubuntu, vì vậy tôi không có hạn chế thực sự nào đối với các công cụ tôi có thể sử dụng. Sẽ rất tốt nếu gửi các giá trị nhị phân thẳng xuống cổng nối tiếp, nhưng tôi có khả năng có thể gửi hai ký tự hex ASCII trên mỗi byte, sau đó chỉnh sửa mã trên đầu thiết bị để đối phó.
Solitaireig666

Câu trả lời:


7

Sử dụng ddhoặc xxd(một phần của Vim), ví dụ để đọc một byte ( -l) tại offset 100 ( -s) từ tệp nhị phân thử:

xxd -p -l1 -s 100 file.bin

để sử dụng offset hex, trong Bash bạn có thể sử dụng cú pháp này $((16#64)), ví dụ:

echo $((16#$(xxd -p -l1 -s $((16#FC)) file.bin)))

trong đó đọc byte ở offset FCvà in nó ở định dạng thập phân.

Hoặc sử dụng dd, như:

dd if=file.bin seek=$((16#FC)) bs=1 count=5 status=none

sẽ kết xuất dữ liệu thô 5 byte ở phần bù hex FC.

Sau đó, bạn có thể gán nó thành biến, tuy nhiên nó sẽ không hoạt động khi dữ liệu của bạn có byte NULL , do đó bạn có thể bỏ qua chúng ( xxd -a) hoặc như cách giải quyết, bạn có thể lưu trữ chúng ở định dạng thập lục phân đơn giản.

Ví dụ:

  1. Đọc 10 byte ở offset 10 thành biến chứa byte ở định dạng hex:

    hex=$(xxd -p -l 10 -s 10 file.bin)
  2. Sau đó viết chúng vào tập tin hoặc thiết bị:

    xxd -r -p > out.bin <<<$hex

Dưới đây là một số hàm hữu ích trong Bash:

set -e

# Read single decimal value at given offset from the file.
read_value() {
  file="$1"
  offset="$2"
  [ -n "$file" ]
  [ -n "$offset" ]
  echo $((16#$(xxd -p -l1 -s $offset "$file")))
}

# Read bytes in hex format at given offset from the file.
read_data() {
  file="$1"
  offset="$2"
  count="$3:-1"
  xxd -p -l $count -s $offset "$file"
}

Sử dụng mẫu:

read_value file.bin $((16#FC)) # Read 0xFC offset from file.bin.

2

Tôi không chắc là tôi hiểu bức tranh lớn về những gì bạn yêu cầu, nhưng tôi có một vài cách tiếp cận mà bạn có thể muốn xem xét:

Sử dụng ddđể đọc tệp đầu vào của bạn

thực hiện 3 < input_file
trong khi sự thật
làm
    dd bs = 1 đếm = 1 <& 3> this_byte
    nếu ! [-s this_byte] # Nếu kích thước bằng 0, chúng ta đã hoàn thành.
    sau đó
        phá vỡ
    fi
    mã bằng tệp this_byte
          ︙
làm xong

Sử dụng odđể tiêu hóa tệp đầu vào của bạn

od -bv input_file | trong khi đọc a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a16
làm # Bỏ qua $ a0; đó là địa chỉ.
    cho byte_val trong "$ a1" "$ a2" "$ a3" "$ a4" "$ a5" "$ a6" "$ a7" "$ a8" "$ a9" "$ a10" \
                                "$ a11" "$ a12" "$ a13" "$ a14" "$ a15" "$ a16"
    làm
        if ["$ byte_val" = ""]
        sau đó
            phá vỡ
        fi
        mã sử dụng giá trị
         $ byte_val chẳng hạn: echo -e "\ 0 $ byte_val \ c"
              ︙
    làm xong
làm xong

1

Điều này có lẽ dễ thực hiện hơn với một chương trình C nhỏ hoặc một (gần như) một lớp trong ngôn ngữ kịch bản như Python hoặc Perl.

Shell Unix là một trình thông dịch cho các lệnh của người dùng , rằng (để thuận tiện trong việc viết các lệnh lặp đi lặp lại) có các phương tiện thô sơ để lập trình. Nó thường được sử dụng (mis) vì một phiên bản của vỏ Bourne được đảm bảo có sẵn trên bất kỳ hệ thống Unix nào, không phải vì nó là ngôn ngữ lập trình đặc biệt tốt (hoặc thậm chí là nửa vời).


0

Bạn có thể sử dụng perlthay thế:

$ printf '%s%s%s' 'ăâé' | LC_ALL=C.UTF-8 perl -Mopen=locale -ne '
    BEGIN { $/ = \1 }
    printf "%s\n", $_;
'
ă
â
é

Bạn đang in cùng một byte trở lại? Theo tôi hiểu, người hỏi muốn biết cách đọc một byte từ một đầu vào, in nó ra đầu ra và sau đó chờ một byte khác từ một đầu vào khác trước khi tiếp tục vòng lặp. Trừ khi đó là những gì bạn làm và tôi không nhận được - điều đó là hoàn toàn có thể.
mikeerv
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.