linux - Bash 将带引号的行拆分为参数

标签 linux bash

希望这个问题以前没有出现过。至少我没有找到答案。也许看起来不太好:(

假设我得到了这段文字:

hello "hello" "hello world"

请告诉我为什么这两个脚本有不同的输出?:

1) 文本保存在文件中

#!/bin/bash
while read line
    do
        set $line
        echo $1
        echo $2
        echo $3
    done < "file"

输出是:

hello
"hello"
"hello

2) 在脚本中硬编码的文本

#!/bin/bash
set hello "hello" "hello world"
echo $1
echo $2
echo $3

这是输出:

hello
hello
hello world

我想在从不同文件读取行时获得第二个行为。请堆垛机帮忙:(

最佳答案

这是一个shell命令:

set hello "hello" "hello world"

因为它是一个 shell 命令,所以 shell 在执行命令之前执行引号删除作为最后一步。

将其与文件中的文本进行对比:

$ cat file
hello "hello" "hello world"

当 shell 读取这个文件时,它把引号当作另一个字符。此文件中的引号从不直接出现在命令行中,因此它们不会被引号删除

文档

摘自 man bash 中讨论扩展的部分:

Quote Removal

After the preceding expansions, all unquoted occurrences of the characters \, ', and " that did not result from one of the above expansions are removed.

分词和删除引号如何相互作用

Bash 在删除引号之前进行分词。这很重要,例如,对于此命令:

set hello "hello" "hello world"

当 shell 进行单词拆分时,它会找到 set 命令的三个参数。只有在执行 set 之前的最后一步,shell 才会删除引号。由于没有进行进一步的单词拆分,因此 set 的参数数量仍为三个。

让我们将上面的内容与从文件中读取一行的结果进行对比:

$ cat file
hello "hello" "hello world"
$ read line <file
$ echo "$line"
hello "hello" "hello world"

如上所述,shell 不会删除 line 的内容的引号。现在,让我们使用 $line 作为 set 的参数:

$ set $line
$ echo $#
4

找到四个参数。这些参数是:

$ echo 1=$1 2=$2 3=$3 4=$4
1=hello 2="hello" 3="hello 4=world"

如您所见,文件中的引号被视为普通字符,例如 he。因此,文件中的 "hello world" 被扩展为两个词,每个词都有一个引号字符。

关于linux - Bash 将带引号的行拆分为参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39233860/

相关文章:

linux - 如何将 expect 与可选提示一起使用?

linux - ubuntu 拒绝 postgres 连接

linux - 将 memcpy 用于 64 位 linux 将内容清零

bash - 用sed替换字符串的一部分

linux - Try...catch 导致带有 posix 线程的嵌入式 ARM 出现段错误

bash - 如何使用 sed 从文件开头打印到所有匹配元素。文件大小大于 25GB

bash - bash/shell 数字上下文中的递归变量扩展从何而来?

bash - 如何在 bash 脚本中运行这两个 heroku 命令?

bash - 在 Bash 中读取键值对,其中值包含定界符

linux - 可变日期在 linux cron 中不起作用