希望此问题之前没有发生过。至少我找不到答案。也许看起来不太好:(
我们假设我收到了这段文字:
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
我想在从不同文件中读取行时获得第二个行为。请堆叠器帮忙:(
答案 0 :(得分:4)
这是一个shell命令:
set hello "hello" "hello world"
因为它是一个shell命令,所以shell在执行命令之前执行 quote removal 作为最后一步。
将其与文件中的文字进行对比:
$ cat file
hello "hello" "hello world"
当shell读取此文件时,它会将引号视为另一个字符。此文件中的引号永远不会直接出现在命令行中,因此它们不受引用删除的约束。
从man bash
讨论扩展的部分:
报价删除
在前面的扩展之后,所有未引用的字符\,'和“的出现都不是由上述之一产生的 扩展被删除。
Bash在引用删除之前会执行分词。例如,这对于此命令很重要:
set hello "hello" "hello world"
当shell执行单词拆分时,它会找到set
命令的三个参数。它只是执行set
之前的最后一步,shell引用删除。由于没有进行进一步的分词,set
的参数数量仍为3。
让我们将上述内容与从文件中读取一行的结果进行对比:
$ 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"
如您所见,文件中的引号仅被视为普通普通字符,与h
或e
相同。因此,文件中的"hello world"
将扩展为两个单词,每个单词都有一个引号字符。
答案 1 :(得分:2)
你可以使用xargs
来做你想要的粗略版本,它会解析引号,反斜杠和c。以大致壳等效的方式:
#!/bin/bash
while IFS= read -r line; do
xargs printf '%s\n' <<<"$line"
done <file
如果您想将这些内容读入位置参数:
#!/bin/bash
while IFS= read -r line; do
set -- # clear the argument list
while IFS= read -r -d '' element; do # read a NUL-delimited element
set -- "$@" "$element" # append to the argument list
done < <(xargs printf '%s\0' <<<"$line") # write NUL-delimited elements
echo "$1" # add quotes to make your code less buggy
echo "$2"
echo "$3"
done <file