【问题标题】:How to remove ^[, and all of the escape sequences in a file using linux shell scripting如何使用 linux shell 脚本删除 ^[ 和文件中的所有转义序列
【发布时间】:2011-09-25 22:44:03
【问题描述】:

我们要删除^[,以及所有转义序列。

sed 不工作,给我们这个错误:

$ sed 's/^[//g' oldfile > newfile; mv newfile oldfile;
sed: -e expression #1, char 7: unterminated `s' command

$ sed -i '' -e 's/^[//g' somefile
sed: -e expression #1, char 7: unterminated `s' command

【问题讨论】:

  • 您是在寻找两个字符,插入符号^ 和左方括号[,还是在寻找一个字符,控制-[(ASCII ESCAPE,0x1B)?您是否要删除 ESC 字符后面的终端控制序列?如果是这样,那是一项复杂的工作,最终需要您知道控制代码是为哪个终端生成的——不同的终端类型使用不同的控制序列,对于单一终端类型,不同的命令具有不同数量的后续字符。跨度>
  • 这不是一个这样的艰巨的任务 - 它部分取决于上下文。

标签: linux shell scripting


【解决方案1】:

您在寻找ansifilter 吗?


您可以做两件事:输入文字转义(在 bash 中:)

使用键盘输入:

sed 's/<kbd>Ctrl-v</kbd><kbd>Esc</kbd>//g'

或者

sed 's/<kbd>Ctrl-v</kbd><kbd>Ctrl-[</kbd>//g'

或者你可以使用字符转义:

sed 's/\x1b//g'

或所有control characters

sed 's/[\x01-\x1F\x7F]//g' # NOTE: zaps TAB character too!

【讨论】:

  • 爱键盘显示+1!
  • ansifilter 很棒的提示! TVM
【解决方案2】:

我在寻找一种从手册页中去除额外格式的方法时偶然发现了这篇文章。 ansifilter 做到了,但与预期的结果相差甚远(例如,所有以前的粗体字符都被重复了,例如 SSYYNNOOPPSSIISS)。

对于该任务,正确的命令是col -bx,例如:

groff -man -Tascii fopen.3 | col -bx > fopen.3.txt

(source)

为什么会这样:(回应@AttRigh 的评论)

groff 像在打字机上一样生成粗体字符:打印一个字母,用退格键向后移动一个字符(您不能在打字机上擦除文本),再次打印相同的字母以使字符更明显。所以简单地省略退格会产生“SSYYNNOOPPSSIISS”。 col -b 通过正确解释退格来解决这个问题,引用手册:

-b不输出任何退格,只打印写入每个列位置的最后一个字符。

【讨论】:

  • 这似乎是 col -b 选项。文档说这会删除退格字符:/,看图。尽管如此,它是我能找到的最紧凑的选项,不需要安装任何东西(在一个包管理器之外)
  • i++ 为此。伙计们,不要重新发明这个轮子。另见colcrt
【解决方案3】:

出于我的目的,我管理了以下内容,但这并不包括所有可能的ANSI escapes

sed -r s/\x1b\[[0-9;]*m?//g

这会删除m 命令,但对于所有转义(如@lethalman 所评论)使用:

sed -r s/\x1b\[[^@-~]*[@-~]//g

另请参阅“https://stackoverflow.com/questions/7857352/python-regex-to-match-vt100-escape-sequences”。

还有一个table of common escape sequences

【讨论】:

  • 这只会转义m 命令。这应该更通用\x1b\[[^@-~]*[@-~]
  • 我特别提到它不是通用的——“......但这不包括所有可能的 ANSI 转义......”
  • [^@-~]*[@-~] 对我不起作用;我需要[^A-Za-z]*[A-Za-z](它似乎与表中所有必需的字符匹配)
  • 请注意,在 BSD (Mac OS X) 上,sed 不支持像 \x1b 这样的 ANSI-C 转义序列。因此,在这些环境中,可能需要通过扩展转义字节来稍微依赖 shell:sed 's/'"$(printf '\x1b')"'\[[^@-~]*[@-~]//g' — 在 bash4 中的 BSD 和 GNU sed 上测试,似乎工作正常。
  • 在我试图删除unbuffer yum search 中的转义序列的情况下,我必须执行sed 's/\x1b\(\[\|(\)[^A-Za-z]*[A-Za-z]//g'(我无法使用-r 的语法)。除了@DavidFraser 的调整,我不仅要删除以\x1b\[ 开头的内容,还要删除以\x1b( 开头的内容。
【解决方案4】:

只是一个注释;假设你有一个这样的文件(这样的行尾是由git 远程报告生成的):

echo -e "remote: * 27625a8 (HEAD, master) 1st git commit\x1b[K
remote: \x1b[K
remote: \x1b[K
remote: \x1b[K
remote: \x1b[K
remote: \x1b[K
remote: Current branch master is up to date.\x1b[K" > chartest.txt

在二进制中,这看起来像这样:

$ cat chartest.txt | hexdump -C
00000000  72 65 6d 6f 74 65 3a 20  2a 20 32 37 36 32 35 61  |remote: * 27625a|
00000010  38 20 28 48 45 41 44 2c  20 6d 61 73 74 65 72 29  |8 (HEAD, master)|
00000020  20 31 73 74 20 67 69 74  20 63 6f 6d 6d 69 74 1b  | 1st git commit.|
00000030  5b 4b 0a 72 65 6d 6f 74  65 3a 20 1b 5b 4b 0a 72  |[K.remote: .[K.r|
00000040  65 6d 6f 74 65 3a 20 1b  5b 4b 0a 72 65 6d 6f 74  |emote: .[K.remot|
00000050  65 3a 20 1b 5b 4b 0a 72  65 6d 6f 74 65 3a 20 1b  |e: .[K.remote: .|
00000060  5b 4b 0a 72 65 6d 6f 74  65 3a 20 1b 5b 4b 0a 72  |[K.remote: .[K.r|
00000070  65 6d 6f 74 65 3a 20 43  75 72 72 65 6e 74 20 62  |emote: Current b|
00000080  72 61 6e 63 68 20 6d 61  73 74 65 72 20 69 73 20  |ranch master is |
00000090  75 70 20 74 6f 20 64 61  74 65 2e 1b 5b 4b 0a     |up to date..[K.|
0000009f

可见git这里在行尾(0x0a)之前添加了序列0x1b0x5b0x4b

请注意 - 虽然您可以在 sed 中将 0x1b 与文字格式 \x1b 匹配,但您不能对代表左方括号 [0x5b 执行相同操作:

$ cat chartest.txt | sed 's/\x1b\x5b//g' | hexdump -C
sed: -e expression #1, char 13: Invalid regular expression

你可能认为你可以用一个额外的反斜杠 \ 来转义表示 - 以 \\x5b 结尾;但是虽然“通过” - 它与预期的任何内容都不匹配:

$ cat chartest.txt | sed 's/\x1b\\x5b//g' | hexdump -C
00000000  72 65 6d 6f 74 65 3a 20  2a 20 32 37 36 32 35 61  |remote: * 27625a|
00000010  38 20 28 48 45 41 44 2c  20 6d 61 73 74 65 72 29  |8 (HEAD, master)|
00000020  20 31 73 74 20 67 69 74  20 63 6f 6d 6d 69 74 1b  | 1st git commit.|
00000030  5b 4b 0a 72 65 6d 6f 74  65 3a 20 1b 5b 4b 0a 72  |[K.remote: .[K.r|
00000040  65 6d 6f 74 65 3a 20 1b  5b 4b 0a 72 65 6d 6f 74  |emote: .[K.remot|
...

所以如果你想匹配这个字符,显然你必须把它写成转义的左方括号,即\[ - 其余的值可以用转义的\x输入符号:

$ cat chartest.txt | sed 's/\x1b\[\x4b//g' | hexdump -C
00000000  72 65 6d 6f 74 65 3a 20  2a 20 32 37 36 32 35 61  |remote: * 27625a|
00000010  38 20 28 48 45 41 44 2c  20 6d 61 73 74 65 72 29  |8 (HEAD, master)|
00000020  20 31 73 74 20 67 69 74  20 63 6f 6d 6d 69 74 0a  | 1st git commit.|
00000030  72 65 6d 6f 74 65 3a 20  0a 72 65 6d 6f 74 65 3a  |remote: .remote:|
00000040  20 0a 72 65 6d 6f 74 65  3a 20 0a 72 65 6d 6f 74  | .remote: .remot|
00000050  65 3a 20 0a 72 65 6d 6f  74 65 3a 20 0a 72 65 6d  |e: .remote: .rem|
00000060  6f 74 65 3a 20 43 75 72  72 65 6e 74 20 62 72 61  |ote: Current bra|
00000070  6e 63 68 20 6d 61 73 74  65 72 20 69 73 20 75 70  |nch master is up|
00000080  20 74 6f 20 64 61 74 65  2e 0a                    | to date..|
0000008a

【讨论】:

    【解决方案5】:

    ansi2txt 命令(kbtin 包的一部分)似乎在 Ubuntu 上完美地完成了这项工作。

    【讨论】:

    • 所以ansi2txt 似乎没有去除粗体字符,而下面列出的使用col -b 的答案(反常地)可以。这是一个测试用例来证明这一点:diff &lt;(man -Tutf8 tmux | col -b | head | hd) &lt;(man -Tutf8 tmux | ansi2txt | head | hd)
    • 看起来像管道 ansi2txtcol -b 是删除所有内容的必要条件。
    • 当管道ansi2txtcol -b 时,您可能需要使用col -xb 来防止空格被制表符替换。但随后制表符将被替换为空格。
    【解决方案6】:

    commandlinefu gives the correct answer 去除 ANSI 颜色以及移动命令:

    sed "s,\x1B\[[0-9;]*[a-zA-Z],,g"
    

    【讨论】:

    • 这适用于 gnu sed,但不能移植到其他 sed 实现(例如 bsd) - 因为 \x1B.对于其他 sed,您可以使用原始转义字符(您可以使用 ctrl-v 前缀在命令行中插入文字转义字符)。
    • Bash 还允许您说 sed $'s,\x1B\[[0-9;]*[a-zA-Z],,g',其中单引号前的美元符号很重要(它会生成“C 风格”字符串)。
    • @tripleee - 谢谢!这有助于 macos(bsd) sed。进一步扩展您的示例: sed $'s,[\x01-\x1F\x7F][[0-9;]*[a-zA-Z],,g" 处理所有转义序列
    • 我在 /var/log/dnf.log 输出中发现了这个 sed 替换左 ^[(B。 AGipson 的那个对我来说效果更好。
    • \x1B\[[?0-9;]*[a-zA-Z]IGNORECASE 成功了。例如,转义码可以是 \x1B[?25? 在这里值得注意。
    【解决方案7】:

    我为此构建了vtclean。它使用这些正则表达式按顺序去除转义序列(在regex.txt 中解释):

    // handles long-form RGB codes
    ^\033](\d+);([^\033]+)\033\\
    
    // excludes non-movement/color codes
    ^\033(\[[^a-zA-Z0-9@\?]+|[\(\)]).
    
    // parses movement and color codes
    ^\033([\[\]]([\d\?]+)?(;[\d\?]+)*)?(.)`)
    

    它还进行基本的行编辑模拟,因此可以解析退格和其他移动字符(如左箭头键)。

    【讨论】:

      【解决方案8】:

      我没有足够的声誉来为Luke H 给出的answer 添加评论,但我确实想分享我一直用来消除所有 ASCII 转义序列的正则表达式。

      sed -r 's~\x01?(\x1B\(B)?\x1B\[([0-9;]*)?[JKmsu]\x02?~~g'
      

      【讨论】:

      • 这适用于 Fedora 的 /var/log/dnf.log 输出,Tom Hale 的答案在输出中留下了 ^[(B
      【解决方案9】:

      您可以使用以下方法删除所有不可打印的字符:

      sed 's/[^[:print:]]//g'

      【讨论】:

      • 在 Mac 上,使用 sed,这是删除 \x1b ascii 转义字符的唯一答案。
      • 但这只会删除不可见的字符;所以像^[[0;31m 这样的东西只会变成[0;31m
      • @tripleee 您可以添加 .... 并删除它们。 's/[^[:print:]]....//g'
      • @rth 不清楚你的提议;精确修剪四个字符是错误的,因为转义序列的长度不同。您必须编写一个转义序列解析器才能知道要删除多少。
      • 即使这样,您也无法知道它是一位数还是两位数,如前面的示例所示。您可以使用 s/[^[:print;]]\[[0-9;]*[A-Za-z]//g 之类的东西来实现它,但我也不确定这是否完全正确。
      【解决方案10】:

      Tom Hale's answer 留下了不需要的代码,但它是一个很好的工作基础。添加额外的过滤清除剩余的不需要的代码:

      sed -e "s,^[[[(][0-9;?]*[a-zA-Z],,g" \
          -e "s/^[[[][0-9][0-9]*[@]//" \
          -e "s/^[[=0-9]<[^>]*>//" \
          -e "s/^[[)][0-9]//" \
          -e "s/.^H//g" \
          -e "s/^M//g" \
          -e "s/^^H//" \
              file.dirty > file.clean
      

      由于这是在非 GNU 版本的 sed 上完成的,您会看到 ^[^H^M,因此我使用了 Ctrl-V 、Ctrl-V Ctrl-H 和 Ctrl -V Ctrl-M 分别。 ^&gt; 字面意思是克拉 (^) 和大于号字符,而不是 Ctrl-<.>

      当时正在使用 TERM=xterm。

      【讨论】:

        【解决方案11】:

        我一直在使用 bash sn-p 来去除(至少一些)ANSI 颜色:

        shopt -s extglob
        while IFS='' read -r line; do
          echo "${line//$'\x1b'\[*([0-9;])[Km]/}"
        done
        

        【讨论】:

          【解决方案12】:

          基于sed 的方法,没有-r 启用的扩展正则表达式

          sed 's/\x1B\[[0-9;]*[JKmsu]//g'
          

          【讨论】:

          • 那个过滤非常复杂的转义码 llike:\033[38;2;255;255;255m 甚至 iconv iconv -f "ASCII" -t "UTF-8" 都失败了。感谢发帖
          • 前 4 个解决方案无效,但这个有效!
          【解决方案13】:

          我的回答

          What are these weird ha:// URLs jenkins fills our logs with?

          有效地从 Jenkins 控制台日志文件中删除所有 ANSI 转义序列(它还处理与此处无关的 Jenkins 特定 URL)。

          我感谢Marius Gedminaspyjama 在此线程中为制定最终解决方案所做的贡献。

          【讨论】:

            【解决方案14】:

            这个简单的 awk 解决方案对我有用,试试这个:

            str="happy $(tput setaf 1)new$(tput sgr0) year!" #colored text
            echo $str | awk '{gsub("(.\\[[0-9]+m|.\\(..\\[m)","",$0)}1' #remove ansi colors
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-12-20
              • 2011-09-25
              • 2015-11-27
              • 2013-12-18
              • 2023-03-23
              • 1970-01-01
              • 2012-06-27
              • 2015-02-04
              相关资源
              最近更新 更多