2009-01-16 56 views
2

我使用zsh作为壳体。如何拆分壳体中的NUL

我想执行一个Unix find命令,并把结果变成一个壳数组变量,像:

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语法的舒适限制,所以我希望有人能够指向我一些我从来不知道但应该知道的基本特征。

回答

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方法的缺点是,当然你没有变量中的文件名。所以这并不总是适用的。

+0

这是我提出的确切示例问题的一个很好的解决方案,谢谢!但我仍然想知道如何将它放入数组中以便重复使用。 – sfink 2009-01-16 22:47:47

1

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

+0

你知道,我以前一直都在使用它。我不确定我是如何摆脱这种习惯的。感谢您的提醒!对于我真正在做的事情,它会工作得很好。但我仍然想知道其他用途的原始问题。 – sfink 2009-01-17 04:07:45

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 [email protected] 
    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 
1

我已经试过

F=(*) 

和它甚至可以处理文件名中带有换行符的文件。