我在 python3 中使用一个小脚本在控制台中显示居中的命运,你能建议我如何在纯 bash 中做到这一点吗?
#!/usr/bin/env python3
import sys, os
linelist = list(sys.stdin)
# gets the biggest line
biggest_line_size = 0
for line in linelist:
line_lenght = len(line.expandtabs())
if line_lenght > biggest_line_size:
biggest_line_size = line_lenght
columns = int(os.popen('tput cols', 'r').read())
offset = biggest_line_size / 2
perfect_center = columns / 2
padsize = int(perfect_center - offset)
spacing = ' ' * padsize # space char
text = str()
for line in linelist:
text += (spacing + line)
divider = spacing + ('?' * int(biggest_line_size)) # unicode 0x2500
text += divider
print(text, end="\n"*2)
Run Code Online (Sandbox Code Playgroud)
.bashrc
使其可执行后chmod +x ~/center.python3
:
fortune | ~/center.python3
Run Code Online (Sandbox Code Playgroud)
编辑:稍后我会尝试根据我的评论回复这个 OP,但现在我让它更有文化。
编辑 2:更新 python 脚本以解决@janos 指出的关于选项卡扩展的错误。
让我们逐块从 Python 转换为 Bash。
Python:
Run Code Online (Sandbox Code Playgroud)#!/usr/bin/env python3 import sys, os linelist = list(sys.stdin)
重击:
#!/usr/bin/env bash
linelist=()
while IFS= read -r line; do
linelist+=("$line")
done
Run Code Online (Sandbox Code Playgroud)
Python:
Run Code Online (Sandbox Code Playgroud)# gets the biggest line biggest_line_size = 0 for line in linelist: line_lenght = len(line) if line_lenght > biggest_line_size: biggest_line_size = line_lenght
重击:
biggest_line_size=0
for line in "${linelist[@]}"; do
# caveat alert: the length of a tab character is 1
line_length=${#line}
if ((line_length > biggest_line_size)); then
biggest_line_size=$line_length
fi
done
Run Code Online (Sandbox Code Playgroud)
Python:
Run Code Online (Sandbox Code Playgroud)columns = int(os.popen('tput cols', 'r').read()) offset = biggest_line_size / 2 perfect_center = columns / 2 padsize = int(perfect_center - offset) spacing = ' ' * padsize # space char
重击:
columns=$(tput cols)
# caveat alert: division truncates to integer value in Bash
((offset = biggest_line_size / 2))
((perfect_center = columns / 2))
((padsize = perfect_center - offset))
if ((padsize > 0)); then
spacing=$(printf "%*s" $padsize "")
else
spacing=
fi
Run Code Online (Sandbox Code Playgroud)
Python:
Run Code Online (Sandbox Code Playgroud)text = str() for line in linelist: text += (spacing + line) divider = spacing + ('?' * int(biggest_line_size)) # unicode 0x2500 text += divider print(text, end="\n"*2)
重击:
for line in "${linelist[@]}"; do
echo "$spacing$line"
done
printf $spacing
for ((i = 0; i < biggest_line_size; i++)); do
printf -- -
done
echo
Run Code Online (Sandbox Code Playgroud)
更容易复制粘贴的完整脚本:
#!/usr/bin/env bash
linelist=()
while IFS= read -r line; do
linelist+=("$line")
done
biggest_line_size=0
for line in "${linelist[@]}"; do
line_length=${#line}
if ((line_length > biggest_line_size)); then
biggest_line_size=$line_length
fi
done
columns=$(tput cols)
((offset = biggest_line_size / 2))
((perfect_center = columns / 2))
((padsize = perfect_center - offset))
spacing=$(printf "%*s" $padsize "")
for line in "${linelist[@]}"; do
echo "$spacing$line"
done
printf "$spacing"
for ((i = 0; i < biggest_line_size; i++)); do
printf ? # unicode 0x2500
done
echo
Run Code Online (Sandbox Code Playgroud)
Bash 中的除法会截断。所以offset
,perfect_center
和的值padsize
可能略有不同。
原始 Python 代码中也存在一些问题:
制表符的长度为 1。这会导致有时分隔线看起来比最长的线短,如下所示:
Q: Why did the tachyon cross the road?
A: Because it was on the other side.
??????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)如果某些线长于columns
,分隔线可能会更好地使用 的长度columns
而不是最长的线。
这是我的脚本center.sh
:
#!/bin/bash\n\nreadarray message < <(expand)\n\nwidth="${1:-$(tput cols)}"\n\nmargin=$(awk -v "width=$width" \'\n { max_len = length > width ? width : length > max_len ? length : max_len }\n END { printf "%" int((width - max_len + 1) / 2) "s", "" }\n\' <<< "${message[@]}")\n\nprintf "%s" "${message[@]/#/$margin}"\n
Run Code Online (Sandbox Code Playgroud)\n\n怎么运行的:
\n\nstdin
数组中message
(感谢@NominalAnimal)width
。如果没有给出参数,则使用实际的终端宽度。message
,awk
以便将左边距作为空格字符串生成,并将其放入变量 中margin
。\n\nmax_len
,最长输入行的长度(上限为width
)(width - max_len) / 2
空白字符message
之后的每一行margin
测试 :
\n\n$ fortune | cowthink | center.sh\n _______________________________________\n ( English literature\'s performing flea. )\n ( )\n ( -- Sean O\'Casey on P. G. Wodehouse )\n ---------------------------------------\n o ^__^\n o (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||\n\n$ echo $\'|\\tTAB\\t|\' | center.sh 20\n | TAB |\n\n$ echo "A line exceeding the maximum width" | center.sh 10\nA line exceeding the maximum width\n
Run Code Online (Sandbox Code Playgroud)\n\n最后,如果您想以分隔线结束显示(就像在 Python 脚本中一样),请在最后一个printf
命令之前添加此行:
message+=( $(IFS=\'\'; sed s/./\xe2\x94\x80/g <<< "${message[*]}" | sort | tail -n1)$\'\\n\' )\n
Run Code Online (Sandbox Code Playgroud)\n\n它的作用是将每行中的每个字符替换为\xe2\x94\x80
,选择最长的字符sort | tail -n1
,并将其添加到消息末尾。
测试:
\n\n$ fortune | center.sh 60\n Tuesday is the Wednesday of the rest of your life.\n \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n
Run Code Online (Sandbox Code Playgroud)\n