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
,\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,而不是开头。使用-0777
forperl
将输入作为包含整个输入的一条记录进行处理。
答案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?
由于 shell 在分配命令替换的输出(例如 )时会从变量末尾吃掉换行符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
没有尾随换行符。我不知道是否有,因为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
上面例子中的。这会就地编辑文件,因此在测试之前备份它。