Cách grep cho unicode trong tập lệnh bash


10
if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt
fi

Về cơ bản, nếu tệp "out.txt" chứa "" bất cứ nơi nào trong tệp tôi muốn nó lặp lại "hoạt động" VÀ nếu tệp "out.txt" KHÔNG chứa "" bất cứ nơi nào trong tệp thì tôi muốn nó để cat out.txt

EDIT: Vì vậy, đây là những gì tôi đang làm. Tôi đang cố gắng vũ phu giải mã openssl.

openssl enc trả về 0 khi thành công, khác không. Lưu ý: bạn sẽ nhận được thông báo sai vì AES / CBC chỉ có thể xác định xem "giải mã có hoạt động" hay không dựa trên việc lấy đúng phần đệm. Vì vậy, tập tin giải mã nhưng nó sẽ không phải là mật khẩu chính xác nên nó sẽ có tiếng vô nghĩa trong đó. Một nhân vật phổ biến trong tiếng vô nghĩa là "". Vì vậy, tôi muốn vòng lặp do tiếp tục nếu đầu ra chứa "".

Đây là liên kết git của tôi https://github.com/Raphaeangelo/OpenSSLCracker Đây là kịch bản

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null && printf "==================================================\n"
if grep -q "�" out.txt
    then
        :
    else
        cat out.txt &&
            printf "\n==================================================" &&
            printfn"\npassword is $line\n" &&
            read -p "press return key to continue..." < /dev/tty; 
fi
done < ./password.txt

nó vẫn hiển thị đầu ra cho tôi với charicter trong đó

CẬP NHẬT: Đã giải quyết

printf "Working..."

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null
if file out.txt | grep -q 'out.txt: ASCII text'
    then
        printf "\n==================================================\n\n" &&
            cat out.txt &&
            printf "\n==================================================" &&
            printf "\npassword is $line\n" && 
            read -p "press return key to continue..." < /dev/tty;
    else
        : 
fi
done < ./password.txt

Có vẻ đúng, nó sẽ hoạt động (btw, tôi không có phông chữ cho ký tự unicode của bạn để xem, nhưng không ai trong số chúng có bất kỳ ý nghĩa đặc biệt nào). greptừ lâu hiểu được unicode (làm cho nó chậm hơn nhiều, vì vậy để tìm kiếm chuỗi ascii, a LANG=C greplà một cải tiến hiệu suất rất lớn).
peterh - Phục hồi Monica

Tôi có thể phải xóa câu hỏi này và đăng một câu hỏi khác vì tôi chắc chắn rằng tôi hoàn toàn nhầm lẫn mọi người ở đây.
Stuart Sloan

@Stuart Sloan tiêu đề của câu hỏi của bạn How to grep for unicode � in a bash scriptlà đây thực sự là những gì bạn muốn? để giải nén unicode? hãy làm rõ để chúng tôi có thể giúp đỡ!

1
@Goro Tôi đã thực hiện chỉnh sửa bài viết gốc của mình. Tôi hy vọng nó có ý nghĩa. Xin vui lòng cho tôi biết nếu nó không và tôi sẽ thử làm rõ.
Stuart Sloan

1
Cả hai câu trả lời hiện tại là vô cùng sai lệch. Xin vui lòng đọc (một lần nữa) câu trả lời của tôi , tôi đã chỉnh sửa nó để giải thích waht là sai với cả hai câu trả lời.
Isaac

Câu trả lời:


27

grep là công cụ sai cho công việc.

Bạn thấy U+FFFD REPLACEMENT CHARACTERkhông phải vì nó thực sự có trong nội dung tệp mà bởi vì bạn đã xem tệp nhị phân với một công cụ được cho là chỉ xử lý đầu vào dựa trên văn bản. Cách tiêu chuẩn để xử lý đầu vào không hợp lệ (nghĩa là dữ liệu nhị phân ngẫu nhiên) là thay thế mọi thứ không hợp lệ trong ngôn ngữ hiện tại (rất có thể là UTF-8) bằng U + FFFD trước khi nó xuất hiện trên màn hình.

Điều đó có nghĩa là rất có khả năng một ký tự \xEF\xBF\xBD(chuỗi byte UTF-8 cho ký tự U + FFFD) không bao giờ xảy ra trong tệp. greplà hoàn toàn đúng khi nói với bạn, không có gì.

Một cách để phát hiện xem một tệp có chứa một số nhị phân không xác định hay không bằng file(1)lệnh:

$ head -c 100 /dev/urandom > rubbish.bin
$ file rubbish.bin
rubbish.bin: data

Đối với bất kỳ loại tập tin không xác định, nó sẽ chỉ đơn giản nói data. Thử

$ file out.txt | grep '^out.txt: data$'

để kiểm tra xem tập tin có thực sự chứa bất kỳ nhị phân tùy ý hay không và do đó rất có thể là rác.

Nếu bạn muốn đảm bảo rằng đó chỉ out.txtlà tệp văn bản được mã hóa UTF-8, bạn có thể sử dụng thay thế iconv:

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null

Bạn hoàn toàn chính xác! thật không may, tôi vẫn nhận được một số rác (ít hơn trước) trong đầu ra.
Stuart Sloan

Có thể filephát hiện một số loại nội dung khác cho các tệp đó. Nếu bạn luôn mong đợi 100% các tệp văn bản được mã hóa UTF-8, bạn có thể kiểm tra xem iconv, nếu một tệp hợp lệ UTF-8 : iconv -f utf-8 -t utf-16 out.txt >/dev/null. Nếu iconvkhông thể chuyển đổi tệp do trình tự UTF-8 không hợp lệ, nó sẽ trả về với mã thoát khác không.
Boldewyn

2
Lệnh tập tin đã đúng! Bạn đã giúp tôi giải quyết vấn đề của tôi nhờ!
Stuart Sloan

4
Tất nhiên, grep "là công cụ cho công việc", hãy thử grep -axv '.*' badchars.txt. Điều đó sẽ in bất kỳ dòng nào chứa bất kỳ Ký tự Unicode không hợp lệ .
Isaac

1
Điều này là vô cùng sai lệch, xin vui lòng đọc trong câu trả lời của tôi về những gì filelàm.
Isaac

5

TL; DR:

grep -axv '.*' out.txt 

câu trả lời dài

Cả hai câu trả lời hiện tại là vô cùng sai lệch và về cơ bản là sai.

Để kiểm tra, Nhận hai tệp này (từ một nhà phát triển được đánh giá rất cao: Markus Kuhn):

$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt
$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt

Bản giới thiệu

Đầu tiên UTF-8-demo.txtlà một tệp được thiết kế để cho thấy UTF-8 có khả năng trình bày nhiều ngôn ngữ, toán học, chữ nổi và nhiều loại ký tự hữu ích khác như thế nào. Hãy xem với một trình soạn thảo văn bản (hiểu utf-8) và bạn sẽ thấy rất nhiều ví dụ và không .

Bài kiểm tra mà một câu trả lời đề xuất: giới hạn phạm vi ký tự \x00-\x7Fsẽ từ chối hầu hết mọi thứ trong tệp này.
Điều đó là rất sai và sẽ không xóa bất kỳ vì không có gì trong tập tin đó .

Sử dụng bài kiểm tra được đề xuất trong câu trả lời đó sẽ xóa 72.5 %tệp:

$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058

Đó là (cho hầu hết các mục đích thực tế) toàn bộ tập tin. Một tập tin được thiết kế rất tốt để hiển thị các ký tự hoàn toàn hợp lệ.

Kiểm tra

Tệp thứ hai được thiết kế để thử một số trường hợp viền để xác nhận rằng các trình đọc utf-8 đang hoạt động tốt. Nó chứa bên trong nhiều ký tự sẽ khiến '' được hiển thị. Nhưng đề nghị trả lời khác (cái được chọn) để sử dụng filekhông thành công với tệp này. Chỉ loại bỏ một byte 0 ( \0) (về mặt kỹ thuật là ASCII hợp lệ) và một \x7fbyte (DEL - xóa) (rõ ràng cũng là một ký tự ASCII) sẽ làm cho tất cả các tệp hợp lệ cho filelệnh:

$ cat UTF-8-test.txt | tr -d '\0\177' > a.txt
$ file a.txt 
a.txt: Non-ISO extended-ASCII text, with LF, NEL line terminators

Không chỉ không filephát hiện nhiều ký tự không chính xác mà còn không phát hiện và báo cáo rằng đó là tệp được mã hóa UTF-8.

Và có, filecó thể phát hiện và báo cáo văn bản được mã hóa UTF-8:

$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text

Ngoài ra, filekhông báo cáo là ASCII, hầu hết các ký tự điều khiển trong phạm vi từ 1 đến 31. Nó ( file) báo cáo một số phạm vi là data:

$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data

Những người khác như ASCII text:

$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text

Là phạm vi ký tự có thể in (với dòng mới):

$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text

Nhưng một số phạm vi có thể gây ra kết quả kỳ lạ:

$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655

Chương trình filekhông phải là một công cụ để phát hiện văn bản, mà là để phát hiện các số ma thuật trong các chương trình hoặc tệp thực thi.

Phạm vi filephát hiện và loại tương ứng được báo cáo tôi tìm thấy là:

  • Giá trị một byte, chủ yếu là ascii:

    {1..6} {14..26} {28..31} 127   :data
    {128..132} {134..159}          :Non-ISO extended-ASCII text
    133                            :ASCII text, with LF, NEL line terminators
    27                             :ASCII text, with escape sequences
    13                             :ASCII text, with CR, LF line terminators
    8                              :ASCII text, with overstriking
    7 {9..12} {32..126}            :ASCII text
    {160..255}                     :ISO-8859 text
    
  • Phạm vi được mã hóa Utf-8:

    {1..6} {14..26} {28..31} 127   :data
    27                             :ASCII text, with escape sequences
    13                             :ASCII text, with CR, LF line terminators
    8                              :ASCII text, with overstriking
    7 {9..12} {32..126}            :ASCII text
    {128..132} {134..159}          :UTF-8 Unicode text
    133                            :UTF-8 Unicode text, with LF, NEL line terminators
    {160..255}                     :UTF-8 Unicode text
    {256..5120}                    :UTF-8 Unicode text
    

Một giải pháp có thể nằm dưới đây.


Trả lời trước.

Giá trị Unicode cho ký tự bạn đang đăng là:

$ printf '%x\n' "'�"
fffd

Đúng, đó là một ký tự Unicode 'ĐẶC ĐIỂM THAY THẾ' (U + FFFD) . Đó là một ký tự được sử dụng để thay thế bất kỳ ký tự Unicode không hợp lệ nào được tìm thấy trong văn bản. Nó là một "trợ giúp trực quan", không phải là một nhân vật thực sự. Để tìm và liệt kê mọi dòng đầy đủ chứa các ký tự UNICODE không hợp lệ, hãy sử dụng:

grep -axv '.*' out.txt 

nhưng nếu bạn chỉ muốn phát hiện nếu có bất kỳ ký tự nào không hợp lệ, hãy sử dụng:

grep -qaxv '.*' out.txt; echo $?

Nếu kết quả là 1tập tin sạch, nếu không sẽ bằng không 0.


Nếu những gì bạn đang hỏi là: làm thế nào để tìm thấy nhân vật, thì, hãy sử dụng điều này:

➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�

Hoặc nếu hệ thống của bạn xử lý chính xác văn bản UTF-8, chỉ cần:

➤ echo "$a" | grep -oP '�'
�

OMG cảm ơn bạn rất nhiều vì grep -axv '.*' !! Tôi đã vật lộn với một vài ký tự xấu trong tệp văn bản của mình và cách khắc phục chúng trong emacs, trong một hoặc hai thập kỷ !!!
nealmcb

3

Câu trả lời rất sớm này là cho bài viết gốc:

Cách grep cho unicode trong tập lệnh bash

if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt  fi

Về cơ bản, nếu tệp "out.txt" chứa "" bất cứ nơi nào trong tệp tôi muốn nó lặp lại "hoạt động" VÀ nếu tệp "out.txt" KHÔNG chứa "" bất cứ nơi nào trong tệp thì tôi muốn nó để cat out.txt

Thử

grep -oP "[^\x00-\x7F]"

với một if .. thentuyên bố như sau:

if grep -oP "[^\x00-\x7F]" file.txt; then
    echo "grep found something ..."
else
    echo "Nothing found!"
fi

Giải thích💡:

  • -P, --perl-regexp: MẪU là biểu thức chính quy Perl
  • -o, --only-matching: chỉ hiển thị một phần của dòng khớp với MẪU
  • [^\x00-\x7F] là một biểu thức chính quy để khớp với một ký tự không phải ASCII.
  • [[:ascii:]] - khớp với một char ASCII duy nhất
  • [^[:ascii:]] - khớp với một char không phải ASCII

trong bash

LC_COLLATE=C grep -o '[^ -~]' file

3
Điều này sẽ phá vỡ (có kết quả dương tính giả) ngay khi ai đó không nói tiếng Anh ...
Kevin

hoặc nếu ai đó cố gắng thảo luận về à la carte, biểu tượng cảm xúc, Pokémon hoặc bất cứ điều gì khác không giới hạn nghiêm ngặt đối với ASCII 7 bit. Tìm kiếm tốt hơn bất cứ thứ gì trong 00-1F, ngoại trừ 09 0A 0D (tab, linefeed, vận chuyển trở lại).
Alcaro

Đây là một ý tưởng rất xấu ver. Điều này sẽ từ chối mọi ký tự Unicode hợp lệ trên phạm vi ASCII, chỉ hơn một triệu ký tự hợp lệ. Kinh ngạc. Hãy thử: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"Chỉ cần 4 ký tự Unicode hợp lệ mà mã của bạn từ chối. :-(
Isaac

Đây là một câu trả lời cực kỳ sai lệch. Xin vui lòng đọc trong câu trả lời của tôi tại sao cách tiếp cận đơn giản chỉ giới hạn ở ASCII không thành công.
Isaac
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.