从 NUL 分隔的文件中删除值

从 NUL 分隔的文件中删除值

v我有一个要从文件中删除的值数组ff以 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,\0转换为 NUL。 (注意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,而不是开头。使用-0777forperl将输入作为包含整个输入的一条记录进行处理。

答案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替换oldnew全局。和\Q确保\E该模式不会被解释为正则表达式。最后,\n?由于 shell 在分配命令替换的输出(例如 )时会从变量末尾吃掉换行符var=$(printf 'foo\n'),所以$i实际上可能不包含最终的换行符。

请注意,这也将匹配子字符串。因此,如果ifoo并且您的文件包含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没有尾随换行符。我不知道是否有,因为cat <<<"$i"即使没有,我也会添加一个。

如果您需要对 shell 数组执行此操作,您可以执行以下操作:

for i in "${foo[@]}"; do 
    export i
    perl -0777 -i -pe 's/\b\Q$ENV{i}\E(\n|\b)//g' file 
done

重要的: 注意-i上面例子中的。这会就地编辑文件,因此在测试之前备份它。

相关内容