如何在 shell 中拆分 NUL

发布于 2024-07-12 03:56:51 字数 468 浏览 6 评论 0原文

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

I am using zsh as a shell.

I would like to execute the unix find command and put the result into a shell array variable, something like:

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

so that I can iterate over the values with something like

for F in "$FILES[@]"; do echo "<<$F>>"; done

However, my filenames contain spaces at least, and perhaps other funky characters, so the above doesn't work. What does work is:

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

but that's fugly. This is already a bit beyond my comfort limit with zsh syntax, so I'm hoping someone can point me to some basic feature that I never knew about but should.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

没有心的人 2024-07-19 03:56:51

我倾向于使用 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 方法的缺点是变量中没有文件名。 所以这并不总是适用。

I tend to use read for that. A quick google search showed me zsh also seem to support that:

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

That doesn't split with zero bytes, but it will make it work with file-names containing whitespace other than newlines. If the file-name appears at the very last of the command to be executed, you can use xargs, working also with newlines in filenames:

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

copies all files found into the directory /tmp/dst. Downside of the xargs approach is that you don't have the filenames in a variable, of course. So this not always applicable.

笑看君怀她人 2024-07-19 03:56:51


我发现的唯一方法是使用 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.'

${(s.\0.)...} 和 ${(s.$'\0'.)...} 不起作用。
您可以使用函数:

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

用法:SplitAt0 varname command [arguments]

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

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

${(s.\0.)...} 和 ${(s.$'\0'.)...} 不起作用。
您可以使用函数:


用法:SplitAt0 varname command [arguments]

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


\0''.)CMDRESULT} )'
}

用法:SplitAt0 varname command [arguments]

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

\0''.)F} )' (zyx:~/tmp) % echo $F[1] ./ 0

${(s.\0.)...} 和 ${(s.$'\0'.)...} 不起作用。
您可以使用函数:

用法:SplitAt0 varname command [arguments]

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


The only way I figured out is using 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.'

${(s.\0.)...} and ${(s.$'\0'.)...} do not work.
You can use function:

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

Usage: SplitAt0 varname command [arguments]

I should have used ${(ps.\0.)F}, not ${(s.\0.)F}:

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

${(s.\0.)...} and ${(s.$'\0'.)...} do not work.
You can use function:


Usage: SplitAt0 varname command [arguments]

I should have used ${(ps.\0.)F}, not ${(s.\0.)F}:


\0''.)CMDRESULT} )'
}

Usage: SplitAt0 varname command [arguments]

I should have used ${(ps.\0.)F}, not ${(s.\0.)F}:

\0''.)F} )' (zyx:~/tmp) % echo $F[1] ./ 0

${(s.\0.)...} and ${(s.$'\0'.)...} do not work.
You can use function:

Usage: SplitAt0 varname command [arguments]

I should have used ${(ps.\0.)F}, not ${(s.\0.)F}:

旧城烟雨 2024-07-19 03:56:51

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

Alternatively, since you're using zsh, you can use zsh's extended globbing syntax to find files rather than using the find command. As far as I know, all the functionality of find is present in the globbing syntax, and it handles filenames with whitespaces properly. See the zshexpn(1) manpage for more info. If you use zsh on a fulltime basis, it's well worth learning the syntax.

一枫情书 2024-07-19 03:56:51

我已经尝试过了

F=(*)

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

I've tried

F=(*)

and it handles even the files with newlines in the filename.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文