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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:44:32  来源:igfitidea点击:

bash difference between raw string and string in variable

stringbashshell

提问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
  1. Why are these being treated differently?
  2. Is there a simple way to iterate through the words in the string without first saving the string as a variable?
  1. 为什么要区别对待这些?
  2. 有没有一种简单的方法来遍历字符串中的单词而无需先将字符串保存为变量?

回答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 -awill divide a string by $IFSand 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 sentencewould be parsed as a single assignment sentence=thisfollowed by an attempt to run a program called is.) As a result, the value of sentencesis 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 wordbeing 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 wordis set to each of the 4words in the list following the inkeyword.

所以 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\oare 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.

引用将任何字符串转换为一个单元。如果您丢失了引号,一切都应该没问题。