对于个人发展和我工作的项目,我们使用四个空格而不是制表符。但是,我需要使用heredoc,而且我不能在不中断缩进流的情况下这样做。
我能想到的唯一可行的方法是:
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上。
发布于 2016-12-07 06:21:53
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
:
$ geta hello <<'EOS'
> hello
> there
>EOS
$ declare -p hello
declare -a hello='([0]="hello" [1]="there")'
gets
$ unset -v hello
$ gets hello <<'EOS'
> hello
> there
> EOS
$ declare -p hello
declare -- hello="hello
there"
这种方法应该适用于任何前导空格字符的组合,只要它们对于所有后续行都是相同的字符。该函数根据第一行中的前导空格字符数,从每行前面剥离相同数量的字符。
所有变量都以下划线开头的原因是为了最大限度地减少与传递的数组名称冲突的机会。您可能希望重写这段代码,以便在它们前面加上一些更不可能发生冲突的内容。
要在OP的函数中使用:
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:
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
}
https://stackoverflow.com/questions/33815600
复制相似问题