3

シェルとして zsh を使用しています。

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 構文での私の快適さの限界をすでに少し超えているため、誰かが私が知らなかったがすべきであるいくつかの基本的な機能を教えてくれることを願っています。

4

4 に答える 4

2

私が理解した唯一の方法は、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
于 2010-02-15T23:46:39.300 に答える
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アプローチの欠点は、変数にファイル名がないことです。したがって、これは常に当てはまるとは限りません。

于 2009-01-16T22:38:12.990 に答える
1

私はもう試した

F=(*)

ファイル名に改行が含まれるファイルも処理します。

于 2012-05-14T00:03:20.047 に答える
1

または、zsh を使用しているため、find コマンドを使用するのではなく、zsh の拡張グロビング構文を使用してファイルを検索できます。私の知る限り、find のすべての機能はグロビング構文に存在し、空白を含むファイル名を適切に処理します。詳細については、zshexpn(1)マンページを参照してください。フルタイムで zsh を使用する場合は、構文を学習する価値があります。

于 2009-01-17T03:07:43.913 に答える