变量中原始字符串和字符串之间的bash差异

时间:2014-11-06 21:31:00

标签: string bash shell

我在bash中编写了一个小脚本,但只有当我将字符串存储为变量时它才有用,我想知道原因。这是摘要:

当我使用字符串本身时,bash将其视为单个实体

for word in "this is a sentence"; do
    echo $word
done
# => this is a sentence

如果我将完全相同的字符串保存到变量中,则bash会迭代单词

sentence="this is a sentence"
for word in $sentence; do
    echo $word
done

# => this
# is
# a
# sentence
  1. 为什么这些被区别对待?
  2. 有没有一种简单的方法来迭代字符串中的单词而不先将字符串保存为变量?

4 个答案:

答案 0 :(得分:3)

如评论所示,报价很重要。 for循环将逐步执行以分号结束的值列表,该列表是一组字符串。不带引号的字符串通常由空格分隔。引用字符串中的空格不会将字符串与其兄弟分开,它只是引用字符串的一部分。在http://mywiki.wooledge.org/Quotes的bash中有一些关于引号的真正优秀的文档。阅读。现在阅读。你会找到一个说

的部分
  

引号实际上并未传递给命令。它们被shell删除(这个过程被巧妙地称为“引用删除”)。

要单步执行存储在变量中的句子中的单词(如果我已正确推断出您的问题),您可以使用数组通过空格分隔单词:

#!/bin/bash

sentence="this is a sentence"
IFS=" " read -a words <<< "$sentence"
for word in "${words[@]}"; do
    echo "$word"
done

在bash中,read -a将字符串除以$IFS,并将分割的部分放入数组的元素中。有关bash数组如何工作的更多信息,请参阅http://mywiki.wooledge.org/BashGuide/Arrays

如果您想了解更多有关特定问题的详细信息,可能需要告诉我们问题所在,或者冒这个问题的风险XY problem

答案 1 :(得分:2)

引号告诉bash在评估表达式时将引号中的内容视为参数列表中的单个参数。引号(除非用\或&#39;保护)将被删除。

echo ""    # prints newlines, no quotes
echo '""'  # Print ""

export X='""'
env | grep X   # X contains ""

export X=""
env | grep X   # X is empty

当你使用变量时,bash按原样解包(就好像你在变量的位置键入了变量的内容)。对于for循环bash,通过用空格分隔for循环参数来确定要迭代的list-elements,但是将(一如既往)引用受保护的项处理为单个参数/ list-element。您的变量不包含引号 - 项目被视为单独的参数。

答案 2 :(得分:2)

在作业中

sentence="this is a sentence"

没有不带引号的空格,因此=右侧的所有内容都被视为单个单词。 (像sentence=this is a sentence这样的东西会被解析为单个赋值sentence=this,然后尝试运行一个名为is的程序。)因此,sentences的值是一个18个字符的序列。它与

完全相同
sentence=this\ is\ a\ sentence

因为再次没有不带引号的空格。

出于同样的原因

for word in "this is a sentence"; do
    echo $word
done

word设置为以下序列中的每个单词,其中只包含一个单词,因为没有不带引号的空格。

与你的另一个循环的关键区别在于参数扩展在事实之后会受到分词的影响。循环

for word in $sentence; do
    echo $word
done
参数扩展后的

for word in this is a sentence; do
     echo $word
done

所以现在word设置为in关键字后面的列表中的每个 4 字词。

目前尚不清楚您在问题的最后提出的问题,但前面的内容是合法代码。不要求在bash中将字符串放在引号中;引号不会将某些内容定义为字符串值,而只是转义引号中出现的每个字符。 "foo"\f\o\o在shell中是相同的。

答案 3 :(得分:0)

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