打印多行文本,空格在第一行对齐

打印多行文本,空格在第一行对齐

问题

我编写了相对复杂的函数,其中必须用空格补充代码。

预计第一行内容(非空格字符)将被确定,从该字符开始到第一个非空格字符为止将被切掉 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:请注意,问题中严格展示输入和输出。

  1. 没有必要提供类似这样的解决方案:

    printf '%s\n' \
        "this is line one" \
        "this is line two" \
        "this is line three"
    
  2. 不需要对我的编程风格等进行分析。

入口和出口都标示得很清楚。我将忽略与主题无关的答案/评论

答案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,除非该行恰好是空格前缀(例如在输入的末尾;这是您的选择)。否则,打印没有正确空格的行(您的选择)。

相关内容