在 zsh 子 shell 内循环中睡眠的替代方案

问题描述 投票:0回答:2

我将 zsh 和 zsh/curses 用于小型命令行界面。当窗口大小改变时,视图的内容应该自动调整。我尝试了使用 trap SIGWINCH 的解决方案,但是使用 zsh(我在 Ubuntu 和 macOS 上尝试过)trap SIGWINCH 显然不起作用。因此,我使用了一个带有繁忙循环的后台 shell(请参阅下面的

monitorwindowsize
),该循环将 SIGUSR1 发送到父 shell 以向其发出信号以调整窗口大小。我发现让内部循环等待一段时间的唯一解决方案是调用
sleep
(例如,调用
read -t 10
在这里不起作用),但是 - 你知道 - sleep 每次被调用时都会创建一个新进程。当然,我想尽可能快地调用 resize 函数,所以我有兴趣保持睡眠时间尽可能短,即经常调用 sleep 。所以我的问题是,在 zsh 下是否有在子 shell 中工作的睡眠替代方案。或者有没有比使用这个 zsh/curses 代码的繁忙循环更好的解决方案。

代码:

#!/bin/zsh

zmodload zsh/curses

loop ()
{
    monitorwindowsize $1 &
    view
    while true; do
        read -t 1000
    done
}

view ()
{
    zcurses addwin mywin $(( LINES-4 )) $(( COLUMNS-4 )) 2 2 
    zcurses clear mywin
    zcurses border mywin
    zcurses refresh mywin
    zcurses move mywin $(( (LINES-4)/2 )) $(( (COLUMNS-8)/2 ))
    zcurses string mywin "Box"
    zcurses refresh mywin
}

resetview ()
{
    zcurses end
    tput clear
    zcurses clear mywin
    zcurses refresh mywin
    zcurses delwin mywin
    view
}

monitorwindowsize ()
{
    currentLines=$LINES
    currentColumns=$COLUMNS
    while true; do
      if (( currentLines != LINES || currentColumns != COLUMNS )); then
        currentLines=$LINES
        currentColumns=$COLUMNS
        kill -SIGUSR1 $1
      fi
      sleep 0.1
    done
}

TRAPUSR1() {
    resetview
}

TRAPINT() {
    for jobs in $jobstates ; do
      jobid=${${jobs##*:*:}%=*}
      kill ${${jobs##*:*:}%=*}
    done
    zcurses end
    exit
}

zcurses init
loop $$
for jobs in $jobstates ; do
  jobid=${${jobs##*:*:}%=*}
  kill ${${jobs##*:*:}%=*}
done
zcurses end

景色:

调整窗口大小后:

command-line-interface posix zsh sleep curses
2个回答
1
投票

您也许可以使用

zselect
。来自
zshmodules
手册页

可以在没有文件描述符和非零的情况下调用

zselect
用作“睡眠”的更细粒度替代品的超时;笔记, 但是,超时返回状态始终为 1。

这里对

zselect
的调用确实出现了半秒的休眠:

> zmodload zsh/zselect
> type zselect
zselect is a shell builtin
> zselect -t 50
>

0
投票

我现在找到了使 SIGWINCH 陷阱起作用的方法:

#!/bin/zsh

zmodload zsh/curses

loop ()
{
    view
    while true; do
        unset raw
        unset key
        zcurses timeout mywin 50
        zcurses input mywin raw key
        now=$(date)
    done
}

view ()
{
    zcurses addwin mywin $(( LINES-4 )) $(( COLUMNS-4 )) 2 2 
    zcurses clear mywin
    zcurses border mywin
    zcurses refresh mywin
    zcurses move mywin $(( (LINES-4)/2 )) $(( (COLUMNS-8)/2 ))
    zcurses string mywin "Box"
    zcurses refresh mywin
}

resetview ()
{
    zcurses end
    tput clear
    zcurses clear mywin
    zcurses refresh mywin
    zcurses delwin mywin
    view
}

TRAPWINCH() {
    resetview
}

TRAPINT() {
    for jobs in $jobstates ; do
      jobid=${${jobs##*:*:}%=*}
      kill ${${jobs##*:*:}%=*}
    done
    zcurses end
    exit
}

zcurses init
loop $$
for jobs in $jobstates ; do
  jobid=${${jobs##*:*:}%=*}
  kill ${${jobs##*:*:}%=*}
done
zcurses end

这取决于

now=$(date)
(也许另一个命令也可以),如果缺少
now=$(date)
,陷阱将不起作用,窗口将不会重绘。

© www.soinside.com 2019 - 2024. All rights reserved.