如何拆分shell中的NUL

时间:2009-01-16 22:31:56

标签: shell zsh

我使用zsh作为shell。

我想执行unix find命令并将结果放入shell数组变量,如:

FILES=($(find . -name '*.bak'))

这样我可以用

之类的东西迭代值
for F in "$FILES[@]"; do echo "<<$F>>"; done

但是,我的文件名至少包含空格,也许还有其他时髦的字符,所以上面的内容不起作用。工作是什么:

IFS=$(echo -n -e "\0"); FILES=($(find . -name '*.bak' -print0)); unset IFS

但那太难了。这已经超出了zsh语法的舒适度,所以我希望有人可以指出一些我从未知道但应该知道的基本功能。

4 个答案:

答案 0 :(得分:2)

我倾向于使用read。一个快速谷歌搜索显示我zsh似乎也支持:

find . -name '*.bak' | while read file; do echo "<<$file>>"; done

不会以零字节分割,但它会使其与包含除换行符之外的空格的文件名一起使用。如果文件名出现在要执行的命令的最后一个位置,则可以使用xargs,同时使用文件名中的换行符:

find . -name '*.bak' -print0 | xargs -0 cp -t /tmp/dst

将找到的所有文件复制到目录/tmp/dst中。当然,xargs方法的缺点是你没有变量中的文件名。所以这并不总是适用。

答案 1 :(得分:1)

或者,由于您使用的是zsh,因此可以使用zsh的扩展globbing语法来查找文件,而不是使用find命令。据我所知,find的所有功能都存在于globbing语法中,它可以正确处理带有空格的文件名。有关详细信息,请参阅zshexpn(1)联机帮助页。如果你在全职的基础上使用zsh,那么学习语法是非常值得的。

答案 2 :(得分:1)

我想出的唯一方法是使用eval:

(zyx:~/tmp) % F="$(find . -maxdepth 1 -name '* *' -print0)"
(zyx:~/tmp) % echo $F | hexdump -C
00000000  2e 2f 20 10 30 00 2e 2f  d0 96 d1 83 d1 80 d0 bd  |./ .0../........|
00000010  d0 b0 d0 bb 20 c2 ab d0  a1 d0 b0 d0 bc d0 b8 d0  |.... ...........|
00000020  b7 d0 b4 d0 b0 d1 82 c2  bb 2e d0 9c d0 b8 d1 82  |................|
00000030  d1 8e d0 b3 d0 b8 d0 bd  d0 b0 20 d0 9e d0 bb d1  |.......... .....|
00000040  8c d0 b3 d0 b0 2e 20 d0  93 d1 80 d0 b0 d0 bd d0  |...... .........|
00000050  b8 20 d0 be d1 82 d1 80  d0 b0 d0 b6 d0 b5 d0 bd  |. ..............|
00000060  d0 b8 d0 b9 2e 68 74 6d  6c 00 2e 2f 0a 20 0a 6e  |.....html../. .n|
00000070  00 2e 2f 20 7b 5b 5d 7d  20 28 29 21 26 7c 00 2e  |../ {[]} ()!&|..|
00000080  2f 74 65 73 74 32 20 2e  00 2e 2f 74 65 73 74 33  |/test2 .../test3|
00000090  20 2e 00 2e 2f 74 74 74  0a 74 74 0a 0a 74 20 00  | .../ttt.tt..t .|
000000a0  2e 2f 74 65 73 74 20 2e  00 2e 2f 74 74 0a 74 74  |./test .../tt.tt|
000000b0  0a 74 20 00 2e 2f 74 74  5c 20 74 0a 74 74 74 00  |.t ../tt\ t.ttt.|
000000c0  2e 2f 0a 20 0a 0a 00 2e  2f 7b 5c 5b 5d 7d 20 28  |./. ..../{\[]} (|
000000d0  29 21 26 7c 00 0a                                 |)!&|..|
000000d6
(zyx:~/tmp) % echo $F[1]
.
(zyx:~/tmp) % eval 'F=( ${(s.'$'\0''.)F} )'
(zyx:~/tmp) % echo $F[1]
./ 0

$ {(s。\ 0。)...}和$ {(s。$'\ 0'。)...}不起作用。 你可以使用功能:

function SplitAt0()
{
    local -r VAR=$1
    shift
    local -a CMD
    set -A CMD $@
    local -r CMDRESULT="$($CMD)"
    eval "$VAR="'( ${(s.'$'\0''.)CMDRESULT} )'
}

用法:SplitAt0 varname command [arguments]

我应该使用${(ps.\0.)F},而不是${(s.\0.)F}

% F=${(ps.\0.)"$(find . -maxdepth 1 -name '* *' -print0)"}
% echo $F[1]
./ 0

答案 3 :(得分:1)

我试过

F=(*)

它甚至可以处理文件名中包含换行符的文件。