NULで区切られたファイルから値を削除する

NULで区切られたファイルから値を削除する

vファイルから削除したい値の配列がありますffNUL で区切られます。どうやって進めますか?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(またはオプションを有効にする必要があります)。$~iglobsubst
  • ${(j:string:)array}:配列の要素をとして連結しますstring。を使用してpNUL\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それはperlNUL-を処理するように指示するのでうまくいきません。終了レコードであるため、$_レコード()の終わりには開始ではなくNULが含まれます。入力全体を含む1つのレコードで入力を処理するには、-0777forを使用します。perl

答え2

入力データによっては、ファイルがメモリに入るのと同じくらい小さいと仮定すると、次のことが役立ちます。

$ export i
$ perl -0777 -pe 's/\Q$ENV{i}\E\n?//g' file 
hi
blue boy

ファイル全体がメモリに入る原因は何ですか-0777perlこれは、$ENV{var}エクスポートされた環境変数にアクセスするPerlの方法です。したがって、$ENV{i}エクスポートされた変数の値が得られますi。グローバルにs/old/new/g置き換えられます。パターンが正規表現として解釈されないことを確認してください。最後に、シェルはコマンド置換(たとえば)の出力を配布するときに変数の末尾に改行文字を食べるため、最後の改行文字は実際に含まれない可能性があります。oldnew\Q\E\n?var=$(printf 'foo\n')$i

これは部分文字列とも一致します。したがって、ファイルが含まれているi場合は削除され、残ります。これを望まない場合は、次のものを使用できます。foofoolishfooish

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上記の例を参照してください。これによりファイルがその場所で編集されるため、テストする前にバックアップしてください。

関連情報