问题:
我编写了相对复杂的函数,其中必须用空格补充代码。
预计第一行内容(非空格字符)将被确定,从该字符开始到第一个非空格字符为止将被切掉 N 个空格。
然后,在随后的所有行中,也将剪掉之前确定的第 N 个空格。
期望示例:
假设有某个print
函数。
在所有后续案例中,我的期望是:
this is the first line,
this is the second line
this is the third line.
所用案例示例:
print '
this is line one
this is line two
this is line three
'
print '
this is line one
this is line two
this is line three
'
tmp() {
tmp2() {
print '
this is line one
this is line two
this is line three
'
}
tmp2
}
tmp
更新型多巴胺:根据对问题答案的分析做法,我又添加了一个测试:
tmp() {
tmp2() {
print '
this
this is line two
this is line three
'
}
tmp2
}
tmp
PS:我的开发(工作不正确)
print() {
INPUT_STRING=$1
# https://stackoverflow.com/questions/41010371/bash-counting-letters-in-string-output-always-a-little-different
COUNT_SPACES_BEFORE_TEXT=$(printf '%s' "${INPUT_STRING}" | grep -o '[^\n]*' | wc -l)
# https://stackoverflow.com/questions/5349718/how-can-i-repeat-a-character-in-bash
STRING_SPACES=$(printf "%${COUNT_SPACES_BEFORE_TEXT}s" |tr " " " ")
# https://stackoverflow.com/questions/23929235/multi-line-string-with-extra-space-preserved-indentation
EXPR_SED='1d;$d;'
EXPR_SED+="s/^${STRING_SPACES}//g"
printf '%s' "${INPUT_STRING}" | sed "${EXPR_SED}"
}
请告诉我该怎么做?
PSS:请注意,问题中严格展示输入和输出。
没有必要提供类似这样的解决方案:
printf '%s\n' \ "this is line one" \ "this is line two" \ "this is line three"
不需要对我的编程风格等进行分析。
入口和出口都标示得很清楚。我将忽略与主题无关的答案/评论
答案1
我不喜欢使用函数的位置参数来传递多行字符串...但如果你总是引用该字符串,那么你就可以实现你想要的纯的(即仅使用 shell 内置命令而不使用外部命令)bash
使用如下函数:
my_print () {
count=1
# Loop over multiline positional argument/s "$*" one line at a time
while IFS= read -r l; do
# Find the number of leading space characters in the first ...
# none empty/blank(all spaces) line and store it in "$spnum"
if [ "$count" -eq "1" ] && [ ! -z "${l// /}" ]; then
l2="${l//[^ ]*/}"
spnum="${#l2}"
count=2
fi
# Print each none empty/blank(all spaces) line ...
# after removing "$spnum" characters from its beginning
[ "$count" -eq "2" ] && [ ! -z "${l// /}" ] && echo "${l:spnum}"
done <<<"$*"
}
使用演示:
$ my_print '
this is line one
this is line two
this is line three
'
this is line one
this is line two
this is line three
$
$ my_print '
this is line one
this is line two
this is line three
'
this is line one
this is line two
this is line three
$
$ tmp() {
tmp2() {
my_print '
this is line one
this is line two
this is line three
'
}
tmp2
}
tmp
this is line one
this is line two
this is line three
$
$ tmp() {
tmp2() {
my_print '
this
this is line two
this is line three
'
}
tmp2
}
tmp
this
this is line two
this is line three
答案2
这是使用 awk 的实现,假设制表符不是空格。
print(){
printf "%s" "$@" |
awk 'BEGIN{ len = -1 }
NF>0 { if(len==-1){
len = index($0,$1)-1;
prefix = substr($0,1,len)
}
}
/./ { start = substr($0,1,len)
if(start==prefix){
if(length($0)>len)print substr($0,len+1)
} else print
}'
}
该字符串通过管道传输到 awk 中,并测试每一行。len
设置为 -1。NF>0
如果该行不全是空格,则为真。$1
保存第一个单词。该单词在行中的索引$0
减 1 是空格前缀字符串的长度。
/./
匹配非空行。第一个len
字符放在 中
start
。如果这与前缀相同,则打印行,从位置 开始len+1
,除非该行恰好是空格前缀(例如在输入的末尾;这是您的选择)。否则,打印没有正确空格的行(您的选择)。