当 IFS 设置为某项时,如何将新行传递给 argv 参数,就像命令输出在此处所做的那样?

How can I pass new lines to an argv parameter when IFS is set to something, the way command output does here?

当 IFS 设置为某项时,我如何将新行传递给 argv 参数,就像这里命令输出的方式一样?

请注意,我这样做是为了尝试弄清楚 unix 中的工作原理。并不是说我实际上想要在 argv 的元素中换行!

我有这个显示 argv 的程序。

$ cat blah.c
#include <stdio.h>

int main(int argc, char *argv[]) {
        int i = 0;
        while (argv[i]) {
                printf("argv[%d] = %s\n", i, argv[i]);
                i++;
        }
        return 0;
}

$


$gcc blah.c -o blah
$

我注意到,如果我将 IFS 设置为等于某个值,甚至只是 IFS= 或 IFS=\n 除默认值 unset IFS 之外的任何值,例如IFS="{" 然后命令输出扩展将多行设置为一个参数,例如到 argv[1]

ubuntu@ubuntu:~/aaa$ IFS="{"
ubuntu@ubuntu:~/aaa$ 
ubuntu@ubuntu:~/aaa$ ./blah `find .`
argv[0] = ./blah
argv[1] = .
./blah
./blah.c
./b
./a

现在,如果我尝试将参数传递给 ./blah,那么我无法在 argv[1] 中获取多行! (我有兴趣做,作为测试)

ubuntu@ubuntu:~/aaa$ ./blah "g h"
argv[0] = ./blah
argv[1] = g h
ubuntu@ubuntu:~/aaa$ ./blah g h
argv[0] = ./blah
argv[1] = g
argv[2] = h
ubuntu@ubuntu:~/aaa$ ./blah g\n h
argv[0] = ./blah
argv[1] = gn
argv[2] = h
ubuntu@ubuntu:~/aaa$ ./blah "g\n h"
argv[0] = ./blah
argv[1] = g\n h
ubuntu@ubuntu:~/aaa$

那么,find . 扩展到什么,即引导多行发送到 argv[1]?

当我尝试将参数传递给程序时无法重现该现象?

当 IFS 不包含 spaces(白色 space)时,命令行上的扩展不会在 spaces 上拆分:

$ var="Hello world"
$ set -x; printf '%s\n' $var; set +x
+ printf '%s\n' Hello world
Hello
world
+ set +x

正如您从 (+) 输出(-x 输出)中看到的那样,参数 $var,一个参数,在 space 上被拆分,并且然后打印为几个参数。

如果 IFS 发生变化:

$ IFS=o
$ set -x; printf '%s\n' $var; set +x
+ printf '%s\n' Hell ' w' rld
Hell
 w
rld
+ set +x

参数的数量和值也发生变化。

find .发生的事情是,当IFS包含一个换行符时,是的,IFS的默认值应该包含一个换行符:

$ printf '%s' "$IFS" | od -tcx1
0000000      \t  \n
         20  09  0a
0000003

查找的输出。 (包括几个换行符)按换行符划分(有效地,换行符被删除)

$ printf '<%s>\n' `find .`
<.>
<./hello>

如果当前目录(pwd)中只有一个名为hello的文件。

但是,如果 IFS 中的换行符被移除,输出不会被分割,它只是 一个 字符串(包含换行符,是的):

$ IFS=x
$ printf '<%s>\n' `find .`
<.
./hello>

效果类似于引用 find , 的扩展:

$ IFS=$' \t\n'                  # return IFS to default in bash.
$ printf '<%s>\n' "`find .`"
<.
./hello>

因此,回答标题的初始问题:

只需使用正确的引号:

$ var='hello world
and some other'
$ printf '<%s>\n' '$var' "$var" $var
<$var>
<hello world
and some other>
<hello>
<world>
<and>
<some>
<other>

这有帮助吗?