将字符串分割成行,然后帧输出

将字符串分割成行,然后帧输出

我一直在研究一种方法来获取字符串,设置最大字符宽度,然后将接近或处于限制的行按单词分割,然后将整个内容框起来。

我设法用printf一个数组和一个for循环来做到这一点,但它很糟糕——尽管它很初级*,而且我每次都必须完成整个事情。

在此输入图像描述

我想创建一个函数并将字符串作为参数传递。我实际上找到了一个关于如何做到这一点的示例,但我不敢使用该代码,因为我无法完全理解它以使其成为我自己的代码,这是必须的,因为我发现的内容无法作为一个参数,它是进程重定向和命令的组合fmt。我无休止地尝试但没有成功,然后我尝试了在的联机帮助页fold中找到的引用。fmt

我想我可以使用此处文档来做到这一点,重定向到文件,然后fmtprintf进行trap清理,但我想不惜一切代价避免使用文件系统。

这就是我得到的,它是printMESSAGEBOX代码中的函数:

#!/usr/bin/env bash

# FORMATING: BOX DRAWING
boxp="                                                                      " ; boxP="                                                                           " ; boxt="      ╭────────────────────────────────────────────────────────────────────────╮" ; boxb="      ╰────────────────────────────────────────────────────────────────────────╯" ; boxT="╭─────────────────────────────────────────────────────────────────────────────╮" ; boxB="╰─────────────────────────────────────────────────────────────────────────────╯" ; boxl="      │ " ; boxL="│ " ; boxr=" │"
# FORMATING: FOREGROUND/TEXT
ñbla () { tput setaf 0;} ; ñred () { tput setaf 1;} ; ñgre () { tput setaf 2;} ; ñyel () { tput setaf 3;} ; ñblu () { tput setaf 4;} ; ñmag () { tput setaf 5;} ; ñcya () { tput setaf 6;} ; ñwhi () { tput setaf 7;}
# FORMATING: BACKGROUND/HIGHLIGHTING
ññbla () { tput setab 0;} ; ññred () { tput setab 1;} ; ññgre () { tput setab 2;} ; ññyel () { tput setab 3;} ; ññblu () { tput setab 4;} ; ññmag () { tput setab 5;} ; ññcya () { tput setab 6;} ; ññwhi () { tput setab 7;}
# FORMATING: MISC (HIGHLIGHT-STANDOUT-ON/HIGHLIGHT-STANDOUT-OFF/RM-STYLE-BOLD-OFF/BOLD-ON/UNDERLINE-ON/UNDERLINE-OFF)
ñH () { tput smso;} ; ñh () { tput rmso;} ; ñ0 () { tput sgr0;} ; alias ñb="ñ0" ; ñB () { tput bold;} ; ñU () { tput smul;} ; ñu () { tput rmul;}
# EXIT CLEANUP
trap ñ0 SIGINT
# MESSAGE PRINTING - REVISED CODE
printBOXHEADER() {
  # SORT OUT INPUT
  while [ "$1" != "" ]; do
    case "$1" in
      --type) shift; type=$1 ;;
      --t0) type=0 ;; # don't print
      --t1) type=1 ;; # green checkmark
      --t2) type=2 ;; # red crossmark
      --t3) type=3 ;; # custom icon
      --t4) type=4 ;; # custom icon, custom color
      --ic) shift; ic=$1 ;;
      --ic-red) ic=red ;; # only obeyed with types 4
      --ic-gre) ic=gre ;; # only obeyed with types 4
      --ic-yel) ic=yel ;; # only obeyed with types 4
      --ic-blu) ic=blu ;; # only obeyed with types 4
      --ic-mag) ic=mag ;; # only obeyed with types 4
      --ic-cya) ic=cya ;; # only obeyed with types 4
      --ic-whi) ic=whi ;; # only obeyed with types 4
      --icon) shift; icon=$1 ;; # single character/emoji, # only obeyed with types 3,4
      --header) shift; header="$1" ;; # optional
    esac
    shift
  done
  # DO THAT THING YOU DO
  if [[ $type -eq 0 ]]; then
    return 0
  elif [[ $type -eq 1 ]]; then
    echo "[$(ñgre) ✔︎ $(ñ0)] $header"
  elif [[ $type -eq 2 ]]; then
    echo "[$(ñred) ✖︎ $(ñ0)] $header"
  elif [[ $type -eq 3 ]]; then
    echo "[ $icon ] $header"
  elif [[ $type -eq 4 ]]; then
    echo "[$(ñ$ic) $icon $(ñ0)] $header"
  fi
}
# MESSAGE PRINTING - HAPHAZARD CODE
msgprint() {
  printf "%s\n" "$boxt"
  for line in "${msg[@]}"; do
    printf "%s%s%s%s\n" "$boxl" "$line" "${boxp:${#line}}" "$boxr"
  done
  printf "%s\n" "$boxb"
}
msgprintw() {
  printf "%s\n" "$boxT"
  for line in "${msg[@]}"; do
    printf "%s%s%s%s\n" "$boxL" "$line" "${boxP:${#line}}" "$boxr"
  done
  printf "%s\n" "$boxB"
}
printMESSAGEBOX() {
  if [[ $widerbox =~ y ]]; then
    msgprintw
  elif [[ $widerbox =~ n ]]; then
    msgprint
  elif [[ $widerbox =~ x ]]; then
    return
  fi
}

widerbox=n
msg=(
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do"
    "eiusmod tempor incididunt ut labore et dolore magna aliqua."
    "Pellentesque nec nam aliquam sem et."
)

printBOXHEADER "$@"
printMESSAGEBOX

输出:

zx9:Scripting v$ messageBOXREVISITING 
      ╭────────────────────────────────────────────────────────────────────────╮
      │ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do        │
      │ eiusmod tempor incididunt ut labore et dolore magna aliqua.            │
      │ Pellentesque nec nam aliquam sem et.                                   │
      ╰────────────────────────────────────────────────────────────────────────╯
zx9:Scripting v$ 

我想让它像printBOXHEADER代码中的函数一样,它最初具有相同的混乱结构printMESSAGEBOX。前导空白是故意存在的,它在使用时与它对齐printBOXHEADER,当不使用时,空白在那里是为了吸引你的注意力。至少这是我们的意图。

我尝试过的事情之一是尝试使用fmt将行拆分为到目前为止我一直在使用的数组,然后使用printf,但我认为我引用错误,因为它要么传递整个字符串,要么将每个单词拆分为它自己的路线,被陷害和没有被陷害的另一次尝试。我已经很接近得到它了......:(

任何事情都受到欢迎和高度赞赏,即使是完全偏离我的方法(只要它仍然使用 Bash 和大多数系统上常见的旧命令来完成,例如; ...... [ ]fmt中的东西)/usr/bin

*:在我的辩护中,我刚刚开始制作脚本:)但即使我缺乏技能,我也可以说它不好。

答案1

你似乎正在重新发明盒子,它是为大多数 Linux 发行版(例如apt-get install boxesdebian、ubuntu 等)打包的。

您可以将文本输入fmt(或者更好的是,标杆) 然后进入boxes.例如

$ par -w 65 < /tmp/lorem | boxes -d stone 
+----------------------------------------------------------------+
| Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed   |
| do eiusmod tempor incididunt ut labore et dolore magna aliqua. |
| Pellentesque nec nam aliquam sem et.                           |
+----------------------------------------------------------------+

注意:boxes当前在其配置文件中不支持多字节字符,请参阅它们的github 问题 #72。这是不幸的,因为有很多漂亮的 unicode 画线字符可用。希望这个问题最终能够得到解决。

boxes但是,它的输入文本支持多字节输入字符。以及 ANSI 转义序列(例如颜色)。但既没有fmt也没有par适当地支持他们。这两个程序都假设一个字符=一个字节

根据维基百科的标准页面以及 1.53 杆的补丁在 par 中添加多字节字符支持,有一个多字节补丁par,但您可能必须自己修补和重建它,因为它尚未合并到上游代码中。

答案2

当启发到来时,我转向刷新其他脚本,这引导我到mapfile.这确实非常简单。

您将文件重定向到数组。

mapfile -t <arbitratyNameForArray> < filename.txt

然而,同样的事情又发生了。它接受一个文件,而我想注入一个变量或即时的东西。

正在阅读Bash 参考手册,一个非常有帮助的ShellCheck 维基,一些我已经失去链接的随机网站等等。我终于得到了。

我只需要更好地确定什么是重定向和什么是替换,特别是在这里:

mapfile -t <arbitratyNameForArray> < <(some process)

ShellCheck Wiki 中给出了答案,实际上有两个,但我仍然尝试做一些我必须确保理解的事情,提出了这个:

msg="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pellentesque nec nam aliquam sem et. Nisi vitae suscipit tellus mauris a diam maecenas sed enim. Sodales ut etiam sit amet nisl purus. Fermentum posuere urna nec tincidunt praesent. Velit dignissim sodales ut eu sem integer vitae justo. Justo donec enim diam vulputate ut pharetra sit amet."

arrayDone=()
while IFS='' read -r line; do
  arrayDone+=("$line")
done < <(fmt -w 76 <(echo "$msg"))


for arrayLine in "${arrayDone[@]}"; do
  printf "%s%s%s\n" "⚡️" "$arrayLine" "↩️"
done

输出:

zx9:Scripting v$ fmtter
⚡️Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod↩️
⚡️tempor incididunt ut labore et dolore magna aliqua. Pellentesque nec nam↩️
⚡️aliquam sem et. Nisi vitae suscipit tellus mauris a diam maecenas sed enim.↩️
⚡️Sodales ut etiam sit amet nisl purus. Fermentum posuere urna nec tincidunt↩️
⚡️praesent. Velit dignissim sodales ut eu sem integer vitae justo. Justo donec↩️
⚡️enim diam vulputate ut pharetra sit amet.↩️
zx9:Scripting v$ 

现在我需要将它应用到我的真实代码中。

怎么运行的

首先,arrayDone=()它只是在使用数组之前简单地声明它。while IFS='' read -r line; do arrayDone+=("$line") done;while启动循环 obvi,IFS=''消除空格字符作为单词分隔符,这是我无休止地阅读应该只在子 shell 中完成或使用一些隔离,否则会导致混乱......知道什么?忘记我所说的一切,我不擅长解释,所以我做了一个涂鸦,与此处文档+重定向到文件进行比较,更容易理解。我希望我能够帮助至少一个人,就像很多在这里帮助过我的人一样。 :)

谢谢!

Bash脚本:将字符串分割成行,然后添加到数组中

相关内容