长答案

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

基本上,如果文件“out.txt”在文件中的任何位置包含“�”,我希望它回显“工作”,并且如果文件“out.txt”在文件中的任何位置不包含“�”,那么我希望它到cat 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

它仍然向我显示带有 � 字符的输出

答案1

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

答案2

长话短说:

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 - 删除)(显然也是一个 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 字符 '替换字符' (U+FFFD)。这是一个用来替换任何字符的字符无效的文本中找到的 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 '�'

答案3

这个非常早期的答案是针对原始帖子的:

如何在 bash 脚本中 grep 查找 unicode �

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

基本上,如果文件“out.txt”在文件中的任何位置包含“�”,我希望它回显“工作”,并且如果文件“out.txt”在文件中的任何位置不包含“�”,那么我希望它到cat 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

解释

答案4

我能够通过使用工具“iconv”执行编码转换和“xxd”将原始二进制转换为十六进制数字来解决这个问题。它将文件转换为 UTF-32 BE(大端)字节流,以便 shell 可以检查真正的 Unicode 字符代码点,而无需包含额外的逻辑。

该示例请求仅检测文件中是否存在单个 Unicode 字符。假设该字符是\u1234abcd(无效,但这只是一个示例)。

# iconv does its best to detect the encoding and convert it to UTF-32 BE
iconv -t utf32be out.txt | \
# xxd turns the raw binary into hex digits and some new lines.
# The '-g 1' attempts to avoid local computer endian-ness by grouping 1
# byte at a time.  It may not be necessary.
xxd -g 1 -R never -ps | \
# 'tr' strips out whitespace generated by 'xxd'.
tr -d '\r\n ' | \
# Loop over each 8 hex digit character.
# This causes the shell to read the input stream
# 8 characters at a time which, if everything above
# went right, is limited to 0-9 and a-f.  LANG=C
# just enforces 1 byte at a time.
while IFS='' LANG=C read -r -d '' -n 8 char ; do
  if [ "${char}" = "1234abcd" ] ; then
    echo "working"
    # No need to scan any other character.  Exit early.
    break
  fi
done

与主要问题不同,上面的答案不会执行后续操作(如果未找到),则 run cat out.txt。这需要将找到的状态传递到内部执行之外。我通常的做法是标记文件是否存在。一些有进取心的人可能会发现一种使用子进程和退出代码更像 grep 的方法。

# Create the marker file.
marker="$( mktemp )"

iconv -t utf32be out.txt | \
xxd -g 1 -R never -ps | \
tr -d '\r\n ' | \
while IFS='' LANG=C read -r -d '' -n 8 char ; do
  if [ "${char}" = "1234abcd" ] ; then
    echo "working"
    # Mark that it was found by removing the temporary file.
    rm "${marker}"
    break
  fi
done

# If the marker file exists, then it wasn't found in the loop.
if [ -f "${marker}" ] ; then
  rm "${marker}"
  cat out.txt
fi

如果您非常小心地只生成十六进制数字并避免字节序转换,则可以使用“od”或“hexdump”代替“xxd”。

“xxd”的优点是提供返回原始数据的反向功能。可以使用“echo -e“\xAf””样式输出来完成同样的事情,但这需要为每个解析的字符生成一个新的回显过程。

我把这个放进去要点以更大的示例来展示它,包括如何将输出重新组装成 UTF 编码流。

相关内容