Jeśli chcesz trzymać się narzędzi powłoki, możesz użyć head
do wyodrębnienia liczby bajtów i od
przekonwertowania bajtu na liczbę.
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)
Nie działa to jednak w przypadku danych binarnych. Istnieją dwa problemy:
Podstawienie polecenia $(…)
usuwa ostatnie znaki nowej linii z wyniku polecenia. Jest dość łatwe obejście: upewnij się, że wynik kończy się znakiem innym niż nowa linia, a następnie usuń ten znak.
string=$(head -c $n; echo .); string=${string%.}
Bash, podobnie jak większość powłok, źle radzi sobie z bajtami zerowymi . Począwszy od wersji bash 4.1 bajty zerowe są po prostu usuwane z wyniku podstawienia polecenia. Dash 0.5.5 i pdksh 5.2 mają to samo zachowanie, a ATT ksh przestaje czytać przy pierwszym bajcie zerowym. Ogólnie rzecz biorąc, powłoki i ich narzędzia nie są przeznaczone do obsługi plików binarnych. (Zsh jest wyjątkiem, jest zaprojektowany do obsługi bajtów zerowych).
Jeśli masz dane binarne, możesz przełączyć się na język taki jak Perl lub Python.
<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
'
Gilles „SO- przestań być zły”
źródło
źródło
read -N
zatrzymuje się na bajty zerowe, więc nie jest to odpowiedni sposób pracy z danymi binarnymi. Ogólnie rzecz biorąc, powłoki inne niż zsh nie radzą sobie z zerami.Jeśli chcesz mieć możliwość radzenia sobie z plikiem binarnym w powłoce, najlepszą opcją (tylko?) Jest praca z narzędziem hexdump .
Tylko do odczytu X bajtów:
Odczytaj długość (i pracuj z 0 jako długością), a następnie „ciąg” jako bajtową wartością dziesiętną:
źródło
AKTUALIZACJA (z perspektywy czasu): ... To pytanie / odpowiedź (moja odpowiedź) sprawia, że myślę o psie, który wciąż goni samochód. Pewnego dnia w końcu dogania samochód. Ok, złapał go, ale on naprawdę nie może wiele z tym zrobić ... Ten anser „łapie” ciągi, ale wtedy nie można wiele z nimi zrobić, jeśli mają osadzone null-bajty ... (więc duża +1 odpowiedź Gillesa .. inny język może być tutaj w porządku).
dd
odczytuje wszystkie dane ... Z pewnością nie zajmie to zera jako „długości” ... ale jeśli masz \ x00 gdziekolwiek w swoich danych, musisz być kreatywny, jak sobie z nimi poradzić;dd
nie ma z tym żadnych problemów, ale twój skrypt powłoki będzie miał problemy (ale zależy to od tego, co chcesz zrobić z danymi) ... Poniższe informacje w zasadzie wypisują każdy „ciąg danych” do pliku z dzielnikiem linii między każdą strin ...btw: Mówisz „znak” i zakładam , że masz na myśli „bajt” ...
ale słowo „znak” stało się dwuznaczne w czasach UNICODE, gdzie tylko 7-bitowy zestaw znaków ASCII używa jednego bajtu na znak ... A nawet w systemie Unicode liczba bajtów różni się w zależności od metody kodowania znaków , np. UTF-8, UTF-16 itp.
Oto prosty skrypt do podkreślenia różnicy między „znakiem” tekstowym a bajtami.
Jeśli twój znak długości ma długość 1-bajta i wskazuje długość bajtu , to ten skrypt powinien załatwić sprawę, nawet jeśli dane zawierają znaki Unicode ...
dd
widzi tylko bajty bez względu na ustawienia regionalne ...Ten skrypt używa
dd
do odczytu pliku binarnego i wyświetla ciągi znaków oddzielone dzielnikiem "====" ... Zobacz dane testowe w następnym skrypciewyjście
Ten skrypt buduje dane testowe, które zawierają 3-bajtowy prefiks w wierszu ...
Prefiks to pojedynczy znak Unicode zakodowany w UTF-8 ...
źródło
/dev/urandom
większości jednorożców. Losowe dane testowe nie są najlepszymi danymi testowymi, dlatego należy zająć się trudnymi przypadkami, takimi jak tutaj puste znaki i znaki nowej linii w miejscach granicznych.Ten po prostu skopiuj plik binarny:
źródło