【问题标题】:pipe the output of a command into less or into cat depending on length根据长度将命令的输出通过管道传输到 less 或 cat
【发布时间】:2010-12-06 16:41:41
【问题描述】:

首先,让我声明这是一个编程 问题(因此不属于超级用户et.al.),因为我说的是shell 编程。这几乎可能是一个高尔夫问题,但我一开始没有答案,所以任何帮助将不胜感激:-)

所以,故事是:我喜欢使用--quit-if-one-screen 选项将内容导入less,因为它非常舒适:less 在不必要的时候不会妨碍我。还是这样?当我的提示已经在我的终端窗口底部时,这个选项完全符合我的要求(即less 的行为类似于cat)。但是,当我当前的提示位于窗口顶部时,less 首先打印大量空白行以 clear 屏幕,然后在屏幕底部打印出我的(短)文件,然后它才意识到文本少于一个屏幕,所以它退出并且我得到了我的提示。

但是这种行为并不好,因为所有那些无用的空白行。我尝试了不同的选项,或者编写了脚本和别名,我能想到的最好的就是这个(我正在使用 zsh,所以 shell 已经能够复制管道等等):

function catless() {
 cat   \
  >>( bucket -$LINES | cat  ) \
  >>( bucket +$LINES | less )
}

bucket 是我刚刚编写的另一个脚本,如果它少于 N 行(带 -N)或多于 N(与+N)。 我把它贴在这里:http://snipt.net/Gyom/copy-stdin-to-stdout-or-not-depending-on-length

ls | catless 几乎可以正常工作。但是,出于同步的原因,这里涉及的不同进程无法正确访问终端,并且一切都在后台执行(特别是,我在这里从来没有得到正确的less,并且提示返回得太快了)。但也许我走错了路。

所以,总而言之,我想要的是这样一个函数/脚本/任何我可以输入 ls | catless 并且当 ls 的输出更短时它的行为完全类似于 ls | cat超过一屏,更长的时候喜欢ls | less

有什么想法吗?

【问题讨论】:

  • 这是个好问题。我认为不可能使用带有文件句柄的 shell 作为管道源/目标来解决它,即使 shell 能够复制句柄。可能使用 Powershell 或 IPython 可能是一种选择,但这只是一种猜测。

标签: shell zsh pager


【解决方案1】:

-X 标志可能会对您有所帮助(来自 less(1)):

  -X or --no-init
         Disables sending the termcap initialization and deinitialization
         strings to the terminal.   This  is  sometimes desirable if the
         deinitialization string does something unnecessary, like
         clearing the screen.

所以,以下应该做你想做的事:

export LESS="-E -X"

或者,既然你喜欢 --quit-if-one-screen,你可以改为:

export LESS="-F -X"

【讨论】:

  • 谢谢。实际上,我的 less 已经具备了所有这些:-) \\ alias less='less --quit-if-one-screen --ignore-case --LONG-PROMPT --SILENT --RAW-CONTROL-CHARS --chop -长线'
  • 酷。顺便说一句,export LESS 更“便携”,因为如果您在登录环境中通过 LESS 设置选项,您将自动在所有 shell 中拥有它,即使它们不是 bash。而且,我喜欢使用“alias m=less”来减少打字:-)
  • LESS=FX 也可以,别名 l="LESS=FX less" 可以用来解决上述问题: ls | l
【解决方案2】:

news for less version 406 中,我看到“不要移动到第一页的屏幕底部。”。你有哪个版本?我的系统版本是382,打印前会移动到屏幕底部(如果只有一屏并且使用-F会导致空行)。

我刚刚安装了版本 436,当给定 -FX 时,它似乎可以满足您的要求(将它与您的其他首选项一起放在 LESS 环境变量中,让任何东西通过运行 less 来使用这些首选项)。

如果你无法获得新版本,你可以试试这个:

function catless() {
    local line buffer='' num=0 limit=$LINES
    while IFS='' read -r line; do
        buffer="$buffer$line"$'\n'
        line=''
        num=$(( num+1 ))
        [[ $num -ge $limit ]] && break
    done
    if [[ $num -ge $limit ]]; then 
        { printf %s "$buffer$line"; cat } | less
    else
        printf %s "$buffer$line"
    fi
}

关键是 shell 必须知道文件中的行数是否比屏幕多,然后它(可能)启动 less(你最初使用的多 io 技术只能在后台运行) .如果 in-shell read 对您来说不够健壮,您可以通过修改代码来替换它:

function cat_up_to_N_lines_and_exit_success_if_more() {
    # replace this with some other implmentation
    # if read -r is not robust enough
    local line buffer='' num=0 limit="$1"
    while IFS='' read -r line; do
        buffer="$buffer$line"$'\n'
        line=''
        num=$(( num+1 ))
        [[ $num -ge $limit ]] && break
    done
    printf %s "$buffer$line"
    [[ $num -ge $limit ]]
}
function catless() {
    local limit=$LINES buffer=''
    # capture first $limit lines
    # the \0 business is to guard the trailing newline
    buffer=${"$(
    cat_up_to_N_lines_and_exit_success_if_more $limit
    ec=$?
    printf '\0'
    exit $ec)"%$'\0'}
    use_pager=$?
    if [[ $use_pager -eq 0 ]]; then
        { printf '%s' "$buffer"; cat } | less
    else
        printf '%s' "$buffer"
    fi
}

【讨论】:

  • 你是对的!我有另一台机器恰好有更少的 418,实际上,''less -FX'' 是什么意思。太感谢了 !我将在旧机器上升级到当前的“更少”,从此过上幸福的生活!
【解决方案3】:

less 有一个 --clear-screen 选项(也可用作 -c。您可能需要检查 $LESS 环境变量以确保它包含该选项。我的没有并且它的行为完全符合您的意愿(而不是您试图克服)。

您可以使用+ad hoc 基础上禁用在$LESS 变量中设置的选项。例如:

less -+c shortfile

您还应该确保$TERM 设置正确。

如果所有其他方法都失败了,请查看man less 的“INPUT PREPROCESSOR”部分中的$LESSOPEN 预处理器和$LESSCLOSE 后处理器功能,看看这是否会导致您采用另一种方法。

【讨论】:

  • 首先,感谢您的回答。第二,该死!它可以在您的系统上运行!但也许这意味着有办法。我没有 $LESS 变量,也没有任何 $LESSOPEN 或 $LESSCLOSE,所以这一面是安全的。关于 $TERM 变量,我记得我曾经在我的 dotfiles 中添加了一个“export TERM=vt100”,因为使用默认的 TERM=xterm,less 用于显示平行宇宙中的所有内容,这些内容过去常常从终端消失退出less。你的 $TERM 是什么?关于+-c,它并没有解决我的问题。但是less 对管道和文件有相同的行为吗?不太确定..
  • 啊。 cmets中没有段落吗?
  • 那将是-+c(首先是连字符),但由于 $LESS 为空/未设置它并不重要(尝试less -c somefile(仅连字符)只是为了看看它的作用)。管道有一些区别(一些程序在发送到管道时,从它们接收时较少)。我的$TERM=xterm-256color。我对$LESSOPEN 的意思是,您可以使用该功能编写脚本来执行您想要的操作(如果可能并且所有其他方法都失败了)。另外,试试less -X somefile$TERM=xterm,看看你是否置身于“平行宇宙”之外。
  • 是的,我首先使用 -+c 和连字符,但没有运气。它似乎没有任何效果。另一方面,-X 确实在当前宇宙中保留较少,所以我可以使用它来代替我的 $TERM 设置。我尝试了所有这些选项的不同组合,但永远无法获得我梦寐以求的行为(即使是在常规文件上)。也许与 OSX 的 Terminal.app 的工作方式有关。无论如何,谢谢你的尝试。我会用一些脚本再试一次,如果我找到答案,我会在这里发布。
猜你喜欢
  • 2019-08-17
  • 1970-01-01
  • 2018-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-19
  • 1970-01-01
相关资源
最近更新 更多