首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >用空格缩进heredocs

用空格缩进heredocs
EN

Stack Overflow用户
提问于 2015-11-20 06:34:13
回答 1查看 19.8K关注 0票数 42

对于个人发展和我工作的项目,我们使用四个空格而不是制表符。但是,我需要使用heredoc,而且我不能在不中断缩进流的情况下这样做。

我能想到的唯一可行的方法是:

代码语言:javascript
复制
usage() {
    cat << '    EOF' | sed -e 's/^    //';
    Hello, this is a cool program.
    This should get unindented.
    This code should stay indented:
        something() {
            echo It works, yo!;
        }
    That's all.
    EOF
}

有没有更好的方法来做这件事?

让我知道这是否应该放在Unix/Linux Stack Exchange上。

EN

回答 1

Stack Overflow用户

发布于 2016-12-07 06:21:53

代码语言:javascript
复制
geta() {
  local _ref=$1
  local -a _lines
  local _i
  local _leading_whitespace
  local _len

  IFS=$'\n' read -rd '' -a _lines ||:
  _leading_whitespace=${_lines[0]%%[^[:space:]]*}
  _len=${#_leading_whitespace}
  for _i in "${!_lines[@]}"; do
    printf -v "$_ref"[$_i] '%s' "${_lines[$_i]:$_len}"
  done
}

gets() {
  local _ref=$1
  local -a _result
  local IFS

  geta _result
  IFS=$'\n'
  printf -v "$_ref" '%s' "${_result[*]}"
}

这是一种稍有不同的方法,由于printf对数组元素进行赋值,因此需要使用Bash 4.1。(对于以前的版本,请替换下面的geta函数)。它处理任意的前导空格,而不仅仅是预定数量的空格。

第一个函数geta从标准输入中读取数据,去掉前导空格,并在传入名称的数组中返回结果。

第二个是gets,它和geta做同样的事情,但是返回一个换行符不变的字符串(最后一个除外)。

如果将现有变量的名称传递给geta,请确保该变量已为空。

如下所示调用geta

代码语言:javascript
复制
$ geta hello <<'EOS'
>    hello
>    there
>EOS
$ declare -p hello
declare -a hello='([0]="hello" [1]="there")'

gets

代码语言:javascript
复制
$ unset -v hello
$ gets hello <<'EOS'
>     hello
>     there
> EOS
$ declare -p hello
declare -- hello="hello
there"

这种方法应该适用于任何前导空格字符的组合,只要它们对于所有后续行都是相同的字符。该函数根据第一行中的前导空格字符数,从每行前面剥离相同数量的字符。

所有变量都以下划线开头的原因是为了最大限度地减少与传递的数组名称冲突的机会。您可能希望重写这段代码,以便在它们前面加上一些更不可能发生冲突的内容。

要在OP的函数中使用:

代码语言:javascript
复制
gets usage_message <<'EOS'
    Hello, this is a cool program.
    This should get unindented.
    This code should stay indented:
        something() {
            echo It works, yo!;
        }
    That's all.
EOS

usage() {
    printf '%s\n' "$usage_message"
}

如前所述,对于早于4.1的Bash:

代码语言:javascript
复制
geta() {
  local _ref=$1
  local -a _lines
  local _i
  local _leading_whitespace
  local _len

  IFS=$'\n' read -rd '' -a _lines ||:
  _leading_whitespace=${_lines[0]%%[^[:space:]]*}
  _len=${#_leading_whitespace}
  for _i in "${!_lines[@]}"; do
    eval "$(printf '%s+=( "%s" )' "$_ref" "${_lines[$_i]:$_len}")"
  done
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33815600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档