如何在bash脚本中为unicode grep


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

基本上,如果文件“ out.txt”在文件中的任何位置都包含“ ...”,我希望它回显“工作”,并且如果文件“ out.txt”在文件中的任何位置均不包含“。”,那么我想它来猫out.txt

编辑:所以这就是我在做什么。我试图蛮力的openssl解密。

openssl enc成功返回0,否则返回非零。注意:您会得到误报,因为AES / CBC只能根据正确的填充来确定“解密是否有效”。因此,该文件将解密,但它不是正确的密码,因此其中会出现乱码。乱码中的常见字符是“。”。因此,如果输出包含“ ...”,我希望do循环继续进行。

这是我的git链接https://github.com/Raphaeangelo/OpenSSLCracker 这是脚本

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

它仍然显示带有``charicter''的输出

更新:已解决

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

它看起来正确,应该可以工作(顺便说一句,我的字体字符看不见字体,但是它们都没有任何特殊含义)。grep长久以来就了解unicode(这会使它变慢很多,因此搜索ascii字符串,LANG=C grep会大大提高性能)。
彼得-恢复莫妮卡

我可能必须删除它并发布另一个问题,因为我确定我完全使这里的所有人感到困惑。
Stuart Sloan

@Stuart Sloan您的问题的标题How to grep for unicode � in a bash script是这真的是您想要的吗?提取unicode?请澄清,以便我们提供帮助!

1
@Goro我已对原始帖子进行了编辑。我希望这是有道理的。请告诉我是否可以,我会尝试澄清一下。
斯图尔特·斯隆

1
目前的两个答案都是极具误导性的。请(再次)阅读我的答案,我已对其进行了编辑以解释这两个答案是否有误。
艾萨克

Answers:


27

grep 是这项工作的错误工具。

您看到了- U+FFFD REPLACEMENT CHARACTER不是因为它确实位于文件内容中,而是因为您使用了应该只能处理基于文本的输入的工具查看了二进制文件。处理无效输入(即,随机二进制数据)的标准方法是,在屏幕上出现之前,用U + FFFD替换当前语言环境中所有无效的内容(最有可能是UTF-8)。

这意味着很可能\xEF\xBF\xBD在文件中永远不会出现文字(U + FFFD字符的UTF-8字节序列)。grep告诉你完全正确,没有。

一种检测文件是否包含未知二进制文件的方法是使用以下file(1)命令:

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

对于任何未知的文件类型,它只会说data。尝试

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

检查文件是否真的包含任意二进制文件,因此很可能是垃圾。

如果要确保out.txt仅是UTF-8编码的文本文件,则可以选择使用iconv

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

你说得对!不幸的是,我仍然在输出中得到一些垃圾(比以前少)。
斯图尔特·斯隆

可能file会检测到这些文件的某些其他内容类型。如果您100%总是只希望使用UTF-8编码的文本文件,则可以使用进行检查iconv,以确认文件是否是有效的UTF-8 :iconv -f utf-8 -t utf-16 out.txt >/dev/null。如果iconv由于无效的UTF-8序列而无法转换文件,则它将返回非零退出代码。
Boldewyn

2
该文件命令是正确的!您帮助我解决了我的问题,谢谢!
斯图尔特·斯隆

4
当然,请尝试grep“是完成任务的工具” grep -axv '.*' badchars.txt。这将打印包含任何无效Unicode字符的任何行。
艾萨克(Isaac)

1
这极具误导性,请阅读我的回答以了解其file作用。
艾萨克(Isaac)

5

TL; DR:

grep -axv '.*' out.txt 

长答案

目前的两个答案都是极具误导性的,而且基本上是错误的。

要进行测试,请获得以下两个文件(来自一个非常有名的开发人员: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

演示版

UTF-8-demo.txt一个文件旨在显示UTF-8能够很好地显示多种语言,数学,盲文和许多其他有用类型的字符。使用文本编辑器(了解utf-8)看一下,您将看到很多示例,没有

一个答案提出的测试:限制字符范围\x00-\x7F将拒绝该文件中的几乎所有内容。
这是非常错误的,并且不会删除任何文件,因为该文件中没有文件

使用该答案中建议的测试将删除72.5 %文件:

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

这是(出于大多数实际目的)整个文件。文件设计得很好,可以显示完全有效的字符。

测试

第二个文件旨在尝试一些边界案例,以确认utf-8读者做得很好。它在内部包含许多字符,这些字符将导致显示“。”。但是file与此文件一起使用的另一个答案推荐(所选的一个)严重失败。仅删除零字节(\0)(从技术上讲是有效的ASCII)和一个\x7f字节(DEL-delete)(显然也为ASCII字符)将使所有文件对file命令有效:

$ 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

不仅file不能检测到许多不正确的字符,而且不能检测并报告它是UTF-8编码的文件。

是的,file能够检测并报告UTF-8编码的文本:

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

另外,file大多数控制字符在1到31范围内都无法以ASCII报告。它(file)报告的某些范围为data

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

其他如ASCII text

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

作为可打印字符范围(带换行符):

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

但是某些范围可能会导致奇怪的结果:

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

该程序file不是检测文本的工具,而是检测可执行程序或文件中的数的工具。

范围file检测,我发现的相应类型的报告是:

  • 一字节值,多数为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
    
  • 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
    

下面是一种可能的解决方案。


先前的答案。

您要发布的字符的Unicode值为:

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

是的,这是Unicode字符'REPLACEMENT CHARACTER'(U + FFFD)。该字符用于替换文本中找到的所有无效 Unicode字符。它是“视觉辅助工具”,而不是真实角色。要查找并列出包含无效UNICODE字符的每一行,请使用:

grep -axv '.*' out.txt 

但是,如果您只想检测是否有任何字符无效,请使用:

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

如果结果是1文件干净,则为零0


如果您要问的是:如何找到角色,请使用此命令:

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

或者,如果系统正确处理了UTF-8文本,则只需:

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

OMG非常感谢您grep -axv '.*' !我已经为文本文件中的一些不良字符以及如何在emacs中修复它们而苦苦挣扎了十年或两年!
nealmcb

3

这个很早的答案是针对原始帖子的:

如何在bash脚本中为unicode grep

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

基本上,如果文件“ out.txt”在文件中的任何位置都包含“ ...”,我希望它回显“工作”,并且如果文件“ out.txt”在文件中的任何位置均不包含“。”,那么我想它来猫out.txt

尝试

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

if .. then声明如下:

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

说明💡:

  • -P--perl-regexp:PATTERN是Perl正则表达式
  • -o--only-matching::仅显示匹配PATTERN的行的一部分
  • [^\x00-\x7F] 是一个正则表达式,用于匹配单个非ASCII字符。
  • [[:ascii:]] -匹配一个ASCII字符
  • [^[:ascii:]] -匹配一个非ASCII字符

bash

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

3
只要有人不说英语,这就会中断(有误报)...
凯文(Kevin)

或者有人尝试讨论点菜,表情符号,神奇宝贝或其他严格限于7位ASCII的内容。最好查找00-1F中的任何内容,但09 0A 0D除外(制表符,换行符,回车符)。
阿尔卡罗(Alcaro)'18年

这是一个非常糟糕的主意。这将拒绝任何超过ASCII范围的有效Unicode字符,仅超过一百万个有效字符。惊人。尝试:printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"仅4个有效的Unicode字符被您的代码拒绝。:-(
艾萨克

这是一个极具误导性的答案。请阅读我的回答,为什么仅限制为ASCII的简单方法会严重失败。
艾萨克(Isaac)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.