Answers:
这里的问题是,您用双引号(“”)包围了变量。删除它,一切正常。
VAR="This displays with \
extra spaces."
echo ${VAR}
输出量
This displays with extra spaces.
这里的问题是,双引号变量会保留所有空白字符。如果您明确需要它,可以使用它。
例如,
$ echo "Hello World ........ ... ...."
将打印
Hello World ........ ... ....
在删除引号时,其不同之处
$ echo Hello World ........ ... ....
Hello World ........ ... ....
此处Bash删除了文本中的多余空格,因为在第一种情况下,整个文本被视为“单个”参数,因此保留了多余的空格。但是在第二种情况下,echo
命令会将文本作为5个参数接收。
在将参数传递给命令时,引用变量也将很有帮助。
在以下命令中,echo
仅获取单个参数为"Hello World"
$ variable="Hello World"
$ echo "$variable"
但是在以下情况下,echo
有两个参数为Hello
和World
$ variable="Hello World"
$ echo $variable
$IFS
是一个强大而通用的工具-但是以这种方式编写的代码永远不会产生任何可靠的结果。
*
?
[]
)开始,扩展变量时不使用引号或早或晚会引起问题。
esuoxu和MickaëlBucas提供的解决方案是执行此操作的常见且更便携式的方法。
这里有一些bash
解决方案(其中一些也可以在其他shell中使用,例如zsh
)。首先,使用+=
append运算符(对于整数变量,常规变量和数组,每种运算符的工作方式略有不同)。
text="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod "
text+="tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, "
text+="quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ..."
如果要在文本中使用换行符(或其他空格/转义符),请使用$''
引号代替:
text=$'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n'
text+=$'...'
接下来,使用printf -v
将格式化的值分配给变量
printf -v text "%s" "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed " \
"do eiusmod empor incididunt ut labore et dolore magna aliqua. "\
"Ut enim ad minim veniam ..."
这里的技巧是参数比格式说明符更多,因此与大多数printf
函数不同,bash会重复使用格式字符串,直到用完为止。您可以\n
在格式字符串中放入a ,或使用$''(或同时使用两者)处理空格。
接下来,使用数组:
text=("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, "
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ..." )
您还可以+=
用来逐行构建文本(请注意()
):
text+=("post script")
不过,在这里,如果您想一次性查看全部文本内容,则必须记住要“展平”数组
echo "$text" # only outputs index [0], the first line
echo "${text[*]}" # output complete text (joined by first character of IFS)
(整数索引数组是隐式排序的,这与关联数组不同),这使您稍有灵活性,因为您可以根据需要操纵线,甚至可以切片和切块。
最后,使用read
或readarray
和“此处文档”:
read -r -d '' text <<-"EOT"
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ...
EOT
readarray -t textarray <<-"EOT"
Lorem [...]
EOT
此处文档的形式<<-
表示从输入中删除了所有前导硬标签,因此您必须使用标签来缩进文本。用引号引起来"EOT"
可防止shell扩展功能,因此逐字使用输入。有了read
它,它使用NUL字节分隔输入,因此它将一口气读取换行符分隔的文本。使用readarray
(aka mapfile
,自bash-4.0起可用),它读入一个数组,并-t
在每行上去除换行符。
read
选项here document
非常好!有助于嵌入python脚本并使用执行python -c
。我script=$(cat <here document>)
以前曾经做过,但是read -r -d '' script <here document>
要好得多。
有一种特殊的heredoc语法,它删除所有行开头的制表符:“ <<-”(请注意添加了破折号)
http://tldp.org/LDP/abs/html/here-docs.html
示例19-4 多行消息,带有制表符
您可以像这样使用它:
v="$(cat <<-EOF
A
B
C
EOF
)"
echo "$v"
结果:
A
B
C
它仅适用于制表符,不适用于空格。
\t
如果您需要标签,效果很好。只是使用echo -e "$v"
而不是echo "$v"
启用反斜杠字符
让外壳吃掉不需要的换行符和以下空格:
$ cat weird.sh
#!/bin/sh
var1="A weird(?) $(
)multi line $(
)text idea. $(
)PID=$$"
var2='You can '$(
)'avoid expansion '$(
)'too: PID=$$'
var3='Or mix it: '$(
)'To insert the PID use $$. '$(
)"It expands to e.g. $$."
echo "$var1"
echo "$var2"
echo "$var3"
$ sh weird.sh
A weird(?) multi line text idea. PID=13960
You can avoid expansion too: PID=$$
Or mix it: To insert the PID use $$. It expands to e.g. 13960.
所以有可能...但是确定喜欢或不喜欢此解决方案只是一个品味问题...
我建议您应该这样做,然后解释原因,但是首先我想谈谈其他事情...
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
这里提供的许多其他解决方案似乎都建议您可以通过更改扩展变量的方式以某种方式影响shell变量的内容。我可以向您保证情况并非如此。
string="some stuff here \
some more stuff here."
echo $string ${#string}
echo "$string" "${#string}"
some stuff here some more stuff here. 53
some stuff here some more stuff here. 53
上面您看到的是首先是一个字段拆分的扩展,然后是扩展源变量的字节数报告,然后是用引号分隔的扩展和相同的字节数。尽管输出可能有所不同,$string
但除了赋值外,shell变量的内容根本不会改变。
更重要的是,如果您不明白为什么会这样,那么您一定会早于此遇到一些令人讨厌的惊喜。让我们再试一次,但条件略有不同。
IFS=sf
echo $string ${#string}
echo "$string" "${#string}"
相同$string
-不同的环境。
ome tu here ome more tu here. 53
some stuff here some more stuff here. 53
字段拆分基于中定义的字段分隔符进行$IFS
。有两种分隔符- $IFS
空格和$IFS
其他任何分隔符。默认情况下$IFS
,将为其分配值空间选项卡换行符 -这是三个可能的$IFS
空格值。但是,您可以轻松地对其进行更改,如您在上面看到的那样,并且可能会对现场拆分扩展产生巨大影响。
$IFS
空格将按顺序移至单个字段-这就是为什么echo
在$IFS
包含空格的情况下扩展包含任何空格序列的扩展将仅求值单个空格的原因-因为echo
将其参数连接到空格。但是,任何非空白值都不会以相同的方式消失,并且每个出现的定界符都会始终获得一个自身的字段-如上述填充扩展所示。
这不是最坏的情况。考虑这其他$string
。
IFS=$space$tab$newline
cd emptydir
string=" * * * \
* * * "
echo $string ${#string}
echo "$string" "${#string}"
* * * * * * 30
* * * * * * 30
看起来还好吧?好吧,让我们再次改变环境。
touch file1 file2 file3 file4 file5
echo $string ${#string}
echo "$string" "${#string}"
file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 30
* * * * * * 30
哇。
默认情况下,如果可以匹配,shell将扩展文件名glob。这发生在参数扩展和按其解析顺序进行字段拆分之后,因此任何未引用的字符串都容易受到这种攻击。您可以根据需要使用来关闭此行为set -f
,但是默认情况下,任何与POSIX兼容的shell始终会显示glob。
这是您在扩展中添加引号以适合缩进首选项时遇到的问题。即使如此,在任何情况下,无论其扩展行为如何,的实际值$string
始终始终是您上一次为其分配时的实际值。让我们回到第一件事。
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
echo "$var" "${#var}"
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like. 70
我相信这是一种使shell语法适应缩进首选项的更明智的方法。我在上面所做的是将每个单独的字符串分配给一个位置参数-每个位置参数都可以由数字(如$1
or)引用${33}
,然后将其连接值分配给$var
使用特殊的shell参数$*
。
$IFS
即使这样,这种方法也不能幸免。不过,我认为这与$IFS
这方面的额外利益有关。考虑:
IFS=\ ;space_split="$*"
IFS=/; slash_split="$*";IFS='
';new_line_split="$*"
echo "$space_split"
echo "$slash_split"
echo "$new_line_split"
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like.
Arg 1: Line 1./Arg 2: Line 2./and so on for/as long as you might like.
Arg 1: Line 1.
Arg 2: Line 2.
and so on for
as long as you might like.
如您所见,$*
将每个arg串联在"$@"
中的第一个字节上$IFS
。因此,在$IFS
为每个保存的值分配不同的值时保存它的值会得到不同的字段分隔符。顺便说一下,您在上面看到的是每个变量的文字值。如果您根本不需要分隔符,则可以执行以下操作:
IFS=;delimitless="$*"
echo "$delimitless" "${#delimitless}"
Arg 1: Line 1.Arg 2: Line 2.and so on foras long as you might like. 67
这是用于设置类似路径的变量的变体:
set -- "${MYDIR}/usr/local/lib" \
:"${MYDIR}/usr/lib" \
:"${MYDIR}/lib" \
"${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export LD_LIBRARY_PATH="$*"
LD_LIBRARY_PATH=$(sed 's/ :/:/g' <<< $LD_LIBRARY_PATH)
使用set
overwrite $@
,可以将其保存并在以后使用,如下所示:
ARGV=("$@")
exec foo "${ARGV[@]}"
该LD_LIBRARY_PATH=$(sed 's/ :/:/g' <<< $LD_LIBRARY_PATH)
行消除了冒号前的空格以及可能的尾随空格。如果仅消除尾随空格,请LD_LIBRARY_PATH=${LD_LIBRARY_PATH%% }
改用。
整个方法是mikeserv出色答案的一种变体。
不要害怕空格字符。在打印多行文本之前,只需删除它们。
$ cat ./t.sh
#!/bin/bash
NEED_HELP=1
if [[ $NEED_HELP -eq 1 ]]; then
lucky_number=$((1 + RANDOM % 10 + 10))
read -r -d '' text <<' EOF'
NAME says hello
Look at this helpful text:
* -**
Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Don't go away, please rate your experience... It'll just take two minutes.
EOF
text=$(echo "$text" | sed -r 's!^\s{4}!!')
text=$(echo "$text" | sed -r "s!\bNAME\b!$0!") # Bash: text=${text//NAME/$0}
text=$(echo "$text" | sed -r "s!\btwo\b!$lucky_number!")
echo "$text"
fi
输出:
$ ./t.sh
./t.sh says hello
Look at this helpful text:
* -**
Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Don't go away, please rate your experience... It'll just take 16 minutes.
无需使用<<-
Heredoc并用制表符将4位空格缩进。