v
ファイルから削除したい値の配列がありますf
。f
NUL で区切られます。どうやって進めますか?sd
使ってみましたが役に立たない。
例:
私はこのファイルを持っています:
# cat -v $attic
^@this is 1.
this is 2.
this is 3.
^@hi
^@blue boy
この変数は次$i
のとおりです。
# cat -v <<<"$i"
this is 1.
this is 2.
this is 3.
このファイルから削除するコマンドを実行したいのですが、$i
結果は次のようになります。
^@hi
^@blue boy
これを試しましたが、FROM="$i" perl -pi -e 's/\0\Q$ENV{FROM}\E//g' "$attic"
複数行があると機能しません$i
。試してみましたFROM="$i" perl -pi0 -e 's/\0\Q$ENV{FROM}\E//g' "$attic"
が、役に立ちませんでした。
答え1
あなたが言及したので、zsh
次のようにすることができます。
zmodload zsh/mapfile
mapfile[$attic]=${(pj:\0:)"${(0@)mapfile[$attic]}":#$i}
$mapfile
モジュールの内部には、zsh/mapfile
ファイル名をその内容にマップする特別な連想配列があります。"${(0@)var}"
:NULに分割します$var
(@
例:内部引用符で空の要素を保持します"$@"
)。${array:#pattern}
。パターンに一致する要素を削除します。ここにある内容は文字通り受け入れられるため、これをモードで処理する必要があります$i
(またはオプションを有効にする必要があります)。$~i
globsubst
${(j:string:)array}
:配列の要素をとして連結しますstring
。を使用してp
NUL\0
に変換します。 (0
上記のパラメータ拡張フラグも作成できますps:\0:
。)
次のようなものが得られますperl
。
FROM=$i perl -0lni -e 'print if $_ ne $ENV{FROM}' -- "$attic"
違いは、perl
まだNULがない場合、最後にNULが追加されることです(一般的な問題-i
(リンクが壊れている、すべてのメタデータを保持していない...))。
より近い内容は次のとおりです。
FROM=$i perl -0777 -F'\0' -pi -e '
$_ = join "\0", grep {$_ ne $ENV{FROM}} @F' -- "$attic"
あなたの
FROM="$i" perl -pi0 -e 's/\0\Q$ENV{FROM}\E//g' "$attic"
次の理由で機能しません。
- in
-pi0
:(バックアップファイル名のサフィックス)0
と見なされるパラメータ-i
- たとえそれを書いたとしても、
-0pi
それはperl
NUL-を処理するように指示するのでうまくいきません。終了レコードであるため、$_
レコード()の終わりには開始ではなくNULが含まれます。入力全体を含む1つのレコードで入力を処理するには、-0777
forを使用します。perl
答え2
入力データによっては、ファイルがメモリに入るのと同じくらい小さいと仮定すると、次のことが役立ちます。
$ export i
$ perl -0777 -pe 's/\Q$ENV{i}\E\n?//g' file
hi
blue boy
ファイル全体がメモリに入る原因は何ですか-0777
?perl
これは、$ENV{var}
エクスポートされた環境変数にアクセスするPerlの方法です。したがって、$ENV{i}
エクスポートされた変数の値が得られますi
。グローバルにs/old/new/g
置き換えられます。パターンが正規表現として解釈されないことを確認してください。最後に、シェルはコマンド置換(たとえば)の出力を配布するときに変数の末尾に改行文字を食べるため、最後の改行文字は実際に含まれない可能性があります。old
new
\Q
\E
\n?
var=$(printf 'foo\n')
$i
これは部分文字列とも一致します。したがって、ファイルが含まれているi
場合は削除され、残ります。これを望まない場合は、次のものを使用できます。foo
foolish
foo
ish
perl -0777 -pe 's/\Q$ENV{i}\E(\n|\b)//g' file
例をテストしてください(交換^@
後\0
)。
$ cat -v file
^@this is 1.
this is 2.
this is 3.
^@hi
^@blue boy
$ export i="$(printf 'this is 1.\nthis is 2.\nthis is 3.\n')"
$ perl -0777 -pe 's/\Q$ENV{i}\n?\E//g' file
hi
blue boy
もちろん、これは$i
末尾の改行がないと仮定します。 1つあるかどうかはわかりません。cat <<<"$i"
なくても一つ追加するからです。
シェル配列を使用してこれを行う必要がある場合は、次のことができます。
for i in "${foo[@]}"; do
export i
perl -0777 -i -pe 's/\b\Q$ENV{i}\E(\n|\b)//g' file
done
重要:-i
上記の例を参照してください。これによりファイルがその場所で編集されるため、テストする前にバックアップしてください。