bash không thể lưu trữ hexvalue 0x00 trong biến


11

Tôi đang cố gắng làm một số thủ thuật với dd. Tôi nghĩ rằng có thể lưu trữ một số giá trị hex trong một biến gọi là "tiêu đề" để chuyển nó thành dd.

Bước đầu tiên của tôi không có biến là đây:

$ echo -ne "\x36\xc9\xda\x00\xb4" |dd of=hex
$ hd hex

00000000  36 c9 da 00 b4                                    |6....|
00000005

Sau đó tôi đã thử điều này:

$ header=$(echo -ne "\x36\xc9\xda\x00\xb4") 
$ echo -n $header | hd

00000000  36 c9 da b4                                       |6...|
00000004

Như bạn thấy tôi đã mất \x00giá trị của mình trong $headerbiến. Có ai có một lời giải thích cho hành vi này? Điều này khiến tôi điên mất.


Tôi nhận được bash: warning: command substitution: ignored null byte in input.
Kusalananda

Bạn đang thiếu dấu ngoặc kép, header="$(echo -ne "\x36\xc9\xda\x00\xb4")"; echo -n "$header" | hdtuy nhiên điều này chỉ cho kết quả tương tự.
ctrl-alt-delor

Điều này hoạt động header="\x36\xc9\xda\x00\xb4"; echo -n "$header" | hd, nhưng không giống như nó đang lưu trữ hình thức có thể đọc được của con người.
ctrl-alt-delor

Câu trả lời:


16

Bạn không thể lưu trữ một byte null trong một chuỗi vì Bash sử dụng các chuỗi kiểu C, dự trữ byte null cho các đầu cuối. Vì vậy, bạn cần phải viết lại tập lệnh của mình để đơn giản chuyển chuỗi chứa byte rỗng mà không cần Bash lưu trữ ở giữa. Ví dụ: bạn có thể làm điều này:

printf "\x36\xc9\xda\x00\xb4" | hd

Nhân tiện, chú ý rằng bạn không cần echo; bạn có thể sử dụng Bash printfcho việc này rất nhiều nhiệm vụ đơn giản khác.

Hoặc thay vì xâu chuỗi, bạn có thể sử dụng tệp tạm thời:

printf "\x36\xc9\xda\x00\xb4" > /tmp/mysequence
hd /tmp/mysequence

Tất nhiên, điều này có vấn đề là tập tin /tmp/mysequencecó thể đã tồn tại. Và bây giờ bạn cần tiếp tục tạo các tệp tạm thời và lưu đường dẫn của chúng theo chuỗi.

Hoặc bạn có thể tránh điều đó bằng cách sử dụng quy trình thay thế:

hd <(printf "\x36\xc9\xda\x00\xb4")

Các <(command)nhà điều hành sẽ tạo ra một đường ống có tên trong hệ thống tập tin, mà sẽ nhận được đầu ra của command. hdsẽ nhận được, như là đối số đầu tiên của nó, đường dẫn đến đường ống mà nó sẽ mở và đọc gần giống như bất kỳ tệp nào. Bạn có thể đọc thêm về nó ở đây: /unix//a/17117/136742 .


1
Trong khi chính xác, đây là một chi tiết thực hiện và không phải là lý do chính xác. Tôi đã xem xét nó, và tiêu chuẩn POSIX thực sự yêu cầu hành vi này, vì vậy bạn có lý do thực sự . (Theo một số người đã chỉ ra, zshsẽ làm điều đó, nhưng chỉ trong chế độ không POSIX.) Tôi thực sự nhìn vào nó bởi vì tôi đã tự hỏi nếu nó là giá trị để thực hiện điều này trong mksh...
mirabilos

@mirabilos, bạn có muốn mở rộng về điều đó không? AFAICT, hành vi không được chỉ định trên mỗi POSIX để thay thế lệnh khi đầu ra có các ký tự NUL và đối với zsh ở chế độ POSIX, sự khác biệt duy nhất tôi có thể nghĩ là trong shmô phỏng, \0không có giá trị mặc định $IFS. echo "$(printf 'a\0b')"vẫn hoạt động tốt trong shthi đua trong zsh.
Stéphane Chazelas

3
@mirabilos Xem xét rằng các vỏ có trước tiêu chuẩn POSIX từ một thập kỷ trở lên, tôi đoán bạn có thể tìm ra lý do thực tế thực tế là các vỏ sử dụng chuỗi kiểu C và tiêu chuẩn được xây dựng xung quanh đó.
giusti

Tôi tìm thấy một Q tốt để thảo luận chi tiết về printf so với echo. unix.stackexchange.com/questions/65804/ Ấn
Paulb

8

Bạn có thể sử dụng zshthay vào đó là lớp vỏ duy nhất có thể lưu trữ ký tự NUL trong các biến của nó. Ký tự đó thậm chí còn có giá trị mặc định là $IFSin zsh.

nul=$'\0'

Hoặc là:

nul=$'\x0'

Hoặc là

nul=$'\u0000'

Hoặc là

nul=$(printf '\0')

Tuy nhiên, lưu ý rằng bạn không thể chuyển một biến như một đối số hoặc biến môi trường cho một lệnh được thực thi dưới dạng các đối số và biến môi trường là các chuỗi được phân định bằng NUL được truyền cho lệnh execve()gọi hệ thống (giới hạn của API của hệ thống, không phải là vỏ ). Trong zsh, bạn tuy nhiên có thể vượt qua NUL byte như các đối số chức năng được xây dựng trong hoặc lệnh.

echo $'\0' # works
/bin/echo $'\0' # doesn't

1
"Bạn có thể sử dụng zsh thay thế". Không, cảm ơn - Tôi đang tự dạy mình bash-scripting như một người mới bắt đầu. Tôi không muốn nhầm lẫn bản thân với một cú pháp khác. Nhưng cảm ơn bạn rất nhiều vì đã gợi ý nó
Frank

Như một vấn đề thực tế, bạn đã sử dụng zshcú pháp trong câu hỏi của bạn. echo -n $headercó nghĩa là để vượt qua các nội dung của các $headerbiến như là một đối số cuối cùng để echo -nzsh(hay fishhay rchay es) cú pháp, không bash cú pháp. Trong bashđó, có một ý nghĩa rất khác nhau . Nói chung zshgiống như ksh( bash, vỏ GNU, ít nhiều là một bản sao của kshvỏ Unix thực tế) nhưng với hầu hết các đặc điểm thiết kế của vỏ Bourne đã được sửa (và rất nhiều tính năng bổ sung, và rất nhiều tính năng bổ sung, và rất nhiều tính năng bổ sung thân thiện với người dùng hơn / ít gây ngạc nhiên hơn).
Stéphane Chazelas

Hãy cẩn thận: đôi khi zsh có thể thay đổi một byte 0: echo $(printf 'ab\0cd') | od -vAn -tx1c in `61 62 20 63 64 0a`, đó là khoảng trống nơi NUL tồn tại.
sorontar

1
Và đó là thứ mà không cái vỏ nào khác (không, không) sẽ sinh sản. Điều đó làm cho một kịch bản hành xử theo những cách rất đặc biệt trong zsh. Theo tôi: zsh chỉ đang cố tỏ ra quá thông minh.
sorontar

2
Đã "sửa" các lỗi sai thiết kế có trong tiêu chuẩn POSIX sh mà quen với việc viết các tập lệnh zsh có nghĩa là người ta đã quen với các thực tiễn sẽ có lỗi nếu được thực hiện trong bất kỳ trình bao nào khác. Đây không phải là một vấn đề với cú pháp không giống với một ngôn ngữ khác mà các kỹ năng hoặc thói quen không có khả năng chuyển giao, nhưng đó không phải là vấn đề trong tay.
Charles Duffy
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.