bash 原始字符串和变量中的字符串之间的bash差异
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26789762/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
bash difference between raw string and string in variable
提问by EthanP
I wrote a little script in bash, but it only worked when I stored the string as a variable, and I'd like to know why. Here's the summary:
我用 bash 写了一个小脚本,但它只在我将字符串存储为变量时才起作用,我想知道为什么。总结如下:
When I use the string itself, bash treats it as a single entity
当我使用字符串本身时,bash 将其视为单个实体
for word in "this is a sentence"; do
echo $word
done
# => this is a sentence
If I save the exact same string into a variable, bash iterates over the words
如果我将完全相同的字符串保存到变量中,bash 将遍历单词
sentence="this is a sentence"
for word in $sentence; do
echo $word
done
# => this
# is
# a
# sentence
- Why are these being treated differently?
- Is there a simple way to iterate through the words in the string without first saving the string as a variable?
- 为什么要区别对待这些?
- 有没有一种简单的方法来遍历字符串中的单词而无需先将字符串保存为变量?
回答by user48956
The quotes tell bash to treat a thing in quotes as a single parameter in a parameter list at the time the expression is evaluated. The quotes (unless protected with \ or ') are removed.
引号告诉 bash 在计算表达式时将引号中的内容视为参数列表中的单个参数。引号(除非用 \ 或 ' 保护)被删除。
echo "" # prints newlines, no quotes
echo '""' # Print ""
export X='""'
env | grep X # X contains ""
export X=""
env | grep X # X is empty
When you use a variable, bash unpacks it as is (i.e. as if you typed the variable's contents in the variable's place). For a for-loop bash determines the list-elements to iterate over by separating the for-loop's parameters by whitespace, but treating (as always) quote-protected items a single parameter/list-element. Your variable contained no quotes -- items are treated as separate parameters.
当您使用一个变量时,bash 会按原样解压缩它(即,就像您在变量的位置键入变量的内容一样)。对于 for 循环,bash 通过用空格分隔 for 循环的参数来确定要迭代的列表元素,但(一如既往)将受引号保护的项目视为单个参数/列表元素。您的变量不包含引号——项目被视为单独的参数。
回答by ghoti
As comments suggested, quotes are important. A for loop will step through a list of values terminated by a semicolon, and that list is a set of strings. Unquoted strings are delimited usually by whitespace. Whitespace inside a quoted string does not separate the string from its brethren, it's simply part of the quoted string. There's some truly excellent documentation about quotes in bash at http://mywiki.wooledge.org/Quotes. Read it. Read it now. You'll find a part that says
正如评论所建议的,引号很重要。for 循环将遍历以分号结尾的值列表,该列表是一组字符串。未加引号的字符串通常由空格分隔。带引号的字符串中的空格不会将字符串与其兄弟分开,它只是带引号的字符串的一部分。http://mywiki.wooledge.org/Quotes 上有一些关于 bash 中引号的非常出色的文档。阅读。现在阅读。你会发现一个部分说
The quotes are not actually passed along to the command. They are removed by the shell (this process is cleverly called "quote removal").
引号实际上并未传递给命令。它们被 shell 删除(这个过程被巧妙地称为“引用删除”)。
To step through the words in a sentence that's stored in a variable (if I've inferred your question correctly), you could perhaps use an array to separate the words by whitespace:
要遍历存储在变量中的句子中的单词(如果我正确推断出您的问题),您也许可以使用数组将单词按空格分隔:
#!/bin/bash
sentence="this is a sentence"
IFS=" " read -a words <<< "$sentence"
for word in "${words[@]}"; do
echo "$word"
done
In bash, read -a
will divide a string by $IFS
and place the divided parts into elements of the array. See http://mywiki.wooledge.org/BashGuide/Arraysfor more information about how bash arrays work.
在 bash 中,read -a
将字符串除以$IFS
并将划分的部分放入数组的元素中。有关bash 数组如何工作的更多信息,请参阅http://mywiki.wooledge.org/BashGuide/Arrays。
If you want more details in pursuit of a specific problem, you might want to tell us what the problem is, or risk making this an XY problem.
如果您想了解更多详细信息以解决特定问题,您可能想告诉我们问题是什么,或者冒着将其变成XY 问题的风险。
回答by chepner
In the assignment
在任务中
sentence="this is a sentence"
there are no unquoted spaces, so everything to the right of the =
is treated as a single word. (Something like sentence=this is a sentence
would be parsed as a single assignment sentence=this
followed by an attempt to run a program called is
.) As a result, the value of sentences
is a sequence of 18 characters. It is identical to
没有未加引号的空格,因此右边的所有内容都=
被视为一个单词。(类似于sentence=this is a sentence
将被解析为单个赋值,sentence=this
然后尝试运行名为 的程序is
。)因此, 的值sentences
是 18 个字符的序列。它等同于
sentence=this\ is\ a\ sentence
because again, there are no unquoted spaces.
因为同样,没有未引用的空格。
For the same reason
出于同样的原因
for word in "this is a sentence"; do
echo $word
done
has word
being set to each word in the following sequence, which only contains a single word because there are no unquoted spaces.
hasword
被设置为以下序列中的每个单词,它只包含一个单词,因为没有未引用的空格。
The key difference with your other loop is that parameter expansions are subject to word-splitting after the fact. The loop
与您的另一个循环的主要区别在于,参数扩展在事后会进行分词。循环
for word in $sentence; do
echo $word
done
after parameter expansion looks like
参数扩展后看起来像
for word in this is a sentence; do
echo $word
done
so now word
is set to each of the 4words in the list following the in
keyword.
所以 nowword
被设置为列表中关键字后面的4 个单词中的每一个in
。
It's not clear what you are actually asking at the end of your question, but the preceding is legal code. There is no requirement that a string be placed in quotes in bash
; quotes do not define something as a string value, but simply escape every character that appears within the quotes. "foo"
and \f\o\o
are the same thing in shell.
不清楚您在问题末尾实际问的是什么,但前面是法律代码。不要求将字符串放在bash
;中的引号中。引号不会将某些内容定义为字符串值,而是简单地转义出现在引号内的每个字符。"foo"
并且\f\o\o
在 shell 中是一样的。
回答by John C
Quoting turns any string into a single unit. If you lose the quotes, everything should be fine.
引用将任何字符串转换为一个单元。如果您丢失了引号,一切都应该没问题。