干净地复制并粘贴到 grep 等命令中,而不会导致终端 echo 使输出混乱?

Riz*_*zer 14 shell grep clipboard

我有一些测试输出,看起来像

PASS: tests/test_mutex_rmw
PASS: tests/test_mutex_trylock
PASS: tests/test_malloc_irreg
FAIL: tests/ARMCI_PutS_latency
FAIL: tests/ARMCI_AccS_latency
PASS: tests/test_groups
PASS: tests/test_group_split
PASS: tests/test_malloc_group
FAIL: tests/test_accs
FAIL: tests/test_accs_dla
Run Code Online (Sandbox Code Playgroud)

我想过滤输出以仅查看失败。只需从屏幕复制文本并粘贴到 stdin 中以传递到 grep 会很方便,例如

grep FAIL
Run Code Online (Sandbox Code Playgroud)

和 Shift-Ctrl-V(或鼠标中键)复制文本。

我想看到的只是

FAIL: tests/ARMCI_PutS_latency
FAIL: tests/ARMCI_AccS_latency
FAIL: tests/test_accs
FAIL: tests/test_accs_dla
Run Code Online (Sandbox Code Playgroud)

但相反,粘贴的输入会显示在屏幕上,并且由于缓冲,输入会与最终输出混合:

$ grep FAIL
PASS: tests/test_mutex_rmw
PASS: tests/test_mutex_trylock
PASS: tests/test_malloc_irreg
FAIL: tests/ARMCI_PutS_latency
FAIL: tests/ARMCI_AccS_latency
PASS: tests/test_groups
PASS: tests/test_group_split
PASS: tests/test_malloc_group
FAIL: teFAIL: tests/ARMCI_PutS_latency
sts/test_accs
FAIL: tests/test_accs_dla
FAIL: tests/ARMCI_AccS_latency
FAIL: tests/test_accs
FAIL: tests/test_accs_dla
Run Code Online (Sandbox Code Playgroud)

对我来说,首先将输入提供给 cat 然后传递给 grep, 是有意义的cat | grep FAIL,但这实际上并没有帮助。缓冲区混合仍然发生。

当然,如果将数据放在传递给 grep 的文件中,则可以干净地过滤它。但我正在寻找的是一个方便的工具,可以简单地对通过剪贴板缓冲区从终端输出复制的文本进行轻度过滤。怎样做最好呢?

同样,如何在不回显到屏幕的情况下完成粘贴(以静默方式提供数据作为命令的标准输入)?

一种方法是显式关闭回显,

stty -echo; grep FAIL; stty echo
Run Code Online (Sandbox Code Playgroud)

这确实有效,但我怀疑有一些方法可以在不切换 stty 的情况下做到这一点。您知道其他基于 shell 的方法吗?

我使用 bash(在 Debian GNU/Linux 上),但 POSIX shell 解决方案也很有趣。

pLu*_*umo 23

用鼠标标记文本,然后使用xclip

xclip -o | grep FAIL
Run Code Online (Sandbox Code Playgroud)

或从剪贴板复制(Ctrl-c):

xclip -selection clipboard -o | grep FAIL
Run Code Online (Sandbox Code Playgroud)

或者:

xclip -sel c -o | grep FAIL
Run Code Online (Sandbox Code Playgroud)

简而言之。

  • `xsel` 是一个非常相似的程序,您可能会研究一下 (4认同)
  • (根据记录,macOS(也是 Unix)具有等效的命令“pbcopy”和“pbpaste”。) (3认同)

Jim*_* L. 17

如果您使用的是 Bournebash或任何其他类似 Bourne 的 shell,则可以使用here-document. 以开始命令grep FAIL << 'EOF'并按 Enter。Bash 将用一个>符号进行提示,以表明需要从终端输入更多命令。然后粘贴您的输入,并EOF在一行中单独输入。的输出grep将出现在该EOF行之后。

$ grep FAIL << 'EOF'
> PASS: tests/test_mutex_rmw
PASS: tests/test_mutex_trylock
PASS: tests/test_malloc_irreg
FAIL: tests/ARMCI_PutS_latency
FAIL: tests/ARMCI_AccS_latency
PASS: tests/test_groups
PASS: tests/test_group_split
PASS: tests/test_malloc_group
FAIL: tests/test_accs
FAIL: tests/test_accs_dla
EOF
FAIL: tests/ARMCI_PutS_latency
FAIL: tests/ARMCI_AccS_latency
FAIL: tests/test_accs
FAIL: tests/test_accs_dla
Run Code Online (Sandbox Code Playgroud)

确保使用EOF任何引用运算符引用 (或其任何部分),以确保此处文档内不会执行参数扩展、命令替换或算术扩展,并且\字符不会被破坏。

为了尽量减少击键次数,您可以这样做:

grep FAIL<<\.
<paste-text-here>
.
Run Code Online (Sandbox Code Playgroud)


roa*_*ima 16

您可以在将所有stdin写入stdoutsponge之前先吸收所有stdin 。(在 Debian 上它位于 package 中。)moreutils

grep FAIL | sponge
Run Code Online (Sandbox Code Playgroud)

或者

sponge | grep FAIL
Run Code Online (Sandbox Code Playgroud)

如果你没有,sponge你可以使用 POSIX 代码实现一个简单的近似,如下所示

#!/bin/sh
[ -n "$1" ] && exec 1>"$1"
umask 077
tmp="${TMPDIR:-/tmp}/${0##*/}.$$.tmp"
cat >"$tmp"
cat "$tmp"
rm -f "$tmp"
Run Code Online (Sandbox Code Playgroud)

您提到您真的希望sponge一个“不回显 stdin 的选项”,它不回显stdin。您所看到的是终端驱动程序的功能,保留为默认回显键入的文本。我倾向于使用这样的函数

esponge() {
    local g ss
    if [ -t 0 ]
    then
        g=$(stty -g)
        stty -echoe
    fi
    sponge "$@"
    ss=$?
    [ -n "$g" ] && stty "$g"
    return $ss
}

esponge | grep FAIL
Run Code Online (Sandbox Code Playgroud)

另一种替代方案但等效于sponge通过发送输入tac(不是 POSIX,但可能安装在某些没有 POSIX 的系统上sponge

tac | tac | grep FAIL
Run Code Online (Sandbox Code Playgroud)

或者用这些 POSIX 替代方案tac之一替换每个实例


Sté*_*las 8

虽然我会采用迄今为止最安全的/方法,但xclipxselzsh在 中,以确保当您将文本粘贴到 中时grep,终端不会回显您键入的内容,因此只能grep看到 的输出,您可以做:

STTY=-echo grep FAIL
Run Code Online (Sandbox Code Playgroud)

然后粘贴您的输入,以Ctrl+结尾d(如果输入不以换行符结尾,则粘贴两次)。

手册中:

STTY
如果在命令环境中设置了此参数,则 shell 会将此参数的值作为参数运行 stty 命令,以便在执行命令之前设置终端。这些模式仅适用于命令,并在命令完成或暂停时重置。如果该命令被挂起并稍后使用 fg 或 wait 内置命令继续,它将看到 STTY 指定的模式,就好像它没有被挂起一样。如果通过“kill -CONT”继续命令,则此(有意)不适用。如果该命令在后台运行,或者该命令位于 shell 环境中但未在输入行中显式分配,则 STTY 将被忽略。这可以避免因意外导出而在每个外部命令中运行 stty。另请注意,STTY 不应用于窗口大小规范;这些不会是命令的本地命令。

您可以通过定义辅助函数在其他类似 POSIX 的 shell 中实现类似的功能(尽管这里不处理暂停),例如:

noecho() (
  saved_tty_settings=$(stty -g)
  trap 'stty "$saved_tty_settings"' INT QUIT EXIT
  stty -echo
  "$@"
)
Run Code Online (Sandbox Code Playgroud)

然后输入:

noecho grep FAIL
Run Code Online (Sandbox Code Playgroud)

更一般地说,将文本粘贴到终端中可能存在危险,即使您不将其作为输入粘贴到 shell 中也是如此。在这里,如果要粘贴的文本首先是从终端仿真器复制的,则风险会更有限,因为终端仿真器不会在剪贴板选择中存储诸如^C/ ^Z/^D控制字符之类的内容。

  • @KamilMaciorowski,这是[POSIX 规范中的一个缺陷](https://www.austingroupbugs.net/view.php?id=1532),将在下一个版本中修复(根据我的要求)。没有任何“stty”实现需要“stty -g”的输出被 split+glob'bed 重新输入,这是没有意义的。 (5认同)
  • 我认为 POSIX-ly `$saved_tty_settings` 不应该用双引号引起来。[POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/stty.html) 允许 `stty -g` 打印“可以用作参数的未指定形式”(复数!);然后它说“所使用的形式不应包含任何需要引用以避免 shell 进行单词扩展的字符”。IMO 这表明某些实现可能需要从未加引号的 `$saved_tty_settings` 中进行分词(即,当双引号引起来时它们将失败),并且没有实现需要将 `$saved_tty_settings` 用双引号引起来。 (2认同)