Bash 从循环输出文本格式

Bash output text formatting from loop

提问人:Calisthenics 提问时间:7/6/2023 更新时间:7/6/2023 访问量:67

问:

我只是想从我运行的单行脚本中清理一些输出,以检查文件是否存在。为了测试,我使用在同一目录上打开的 2 个不同的终端并运行一个连续的“while true 循环”来检查文件是否存在,以及 if 语句有条件地输出消息,同时让另一个终端生成并删除测试文件用于测试。

航站楼-1dir: $ rm file ; sleep 10 ; touch file

航站楼-2dir: $ while true ; do if [[ -e $file ]] ; then echo -e "\e[1;32m FILE EXISTS\e[0m" ; break ; else echo -en "\e[1;31m FILE DOES NOT EXIST YET\e[0m\r" ; fi ; done

最终发生的事情是,我在 else 条件下获得了我想要的输出,因为“FILE DOES NOT EXIST”,但是当“”消息出现时,它会覆盖第一个但仅覆盖字符串的长度,所以我会得到”FILE EXISTS FILE EXISTSOT EXIST"

ChatGPT一直无济于事。有人有什么提示吗?我正在使用第二个回声,并将其全部保持在一行上,并可作为输出到终端进行管理,直到我收到我的 FILE EXISTS 消息。我希望它在同一条线上都干净,并且在第一个回声上使用相同的回声无济于事。-n\r-n\r

bash while-loop 回声

评论

3赞 pjh 7/6/2023
尝试添加 8 个空格,以便它们覆盖上一条消息的末尾。FILE EXISTS
0赞 Shawn 7/6/2023
尝试在文件存在的回声的开头添加一个(擦除某些终端上的当前行)\e[2K
0赞 William Pursell 7/6/2023
代替 ,你可以写while true; do if [[ -e $file ]]; ... break;while ! [[ -e $file ]]; do ...
2赞 F. Hauri - Give Up GitHub 7/6/2023
我认为您必须查看 inotify 库在 shell 脚本中使用 inotifywait
1赞 F. Hauri - Give Up GitHub 7/6/2023
在 之前或之后添加 。\e[K\e[0m

答:

0赞 user1934428 7/6/2023 #1

您永远不会擦除该行,因此,如果您在较长的文本上写较短的文本,则部分旧文本将保持可见。

你可以做一个

tput el

(el= 从光标清除到行尾)在打印新文本之前。

0赞 Léa Gris 7/6/2023 #2

使用代替,因为前者是标准的,而不是后者。printfecho -en

#!/usr/bin/env sh

file=$1

while :; do
  if [ -e "$file" ]; then
    printf '\e[1;32mFILE EXISTS\e[0m\e[K\n'
    break
  else
    sleep .2
    printf '\e[1;31mFILE DOES NOT EXIST YET\e[0m\r'
  fi
done

此外,使用可能是监视文件创建事件的更明智的选择。inotifywait

在那里,循环只针对每个创建事件运行,因此不会忙于加载 CPU 探测文件以实现。

#!/usr/bin/env sh

filePath=$1
baseDir=${filePath%/*}
[ "$baseDir" = "$filePath" ] && baseDir=./

while
  ! [ -e "$filePath" ] && 
  printf '\r\e[1;31mFILE DOES NOT EXIST YET\e[0m'
do
  inotifywait -qqe create "$baseDir"
done

printf '\r\e[1;32mFILE EXISTS\e[0m\e[K\n'

评论

1赞 F. Hauri - Give Up GitHub 7/6/2023
通过在行前添加,可以使它们闪烁。如果您仅在打印后清除,您会得到更好的效果:\e[Kprintf '\e[1;32mFILE EXISTS\e[0m\e[K\n'
0赞 Léa Gris 7/6/2023
@F.Hauri-GiveUpGitHub 根据您的建议进行了修改并添加了inotifywait
0赞 kvantour 7/6/2023 #3

最简单的方法是使用:

printf "\r\e[K\e[1;32m%-*s\e[0m\n" "${COLUMNS}" 'FILE EXIST'

因此,结合起来,这将创建以下脚本:

printf '\e[1;31mFILE DOES NOT EXIST YET\e[0m'
while ! [ -e "$file" ]: do sleep 1; done
printf "\r\e[K\e[1;32m%-*s\e[0m\n" "${COLUMNS}" 'FILE EXIST'

在这里,我们避免连续写同一行

注意;请注意,它不会删除一行,它只是执行 carage 返回。如果将输出重定向到文件,原始数据仍将存在。\r

详细信息在这里: 有没有比回声 “ ” 更好的擦除线条的方法?