使用 sed 命令从多个文件中删除行

Removing lines from multiple files with sed command

所以,免责声明:我对使用 bash 和 zsh 还很陌生,所以答案可能真的很简单。尽管如此。我检查了以前的帖子,但找不到任何东西。 (编辑:我在 bash 和 zsh shell 中都尝试过这个——同样的问题。)

我有一个包含许多文件的目录,我正在尝试从每个文件中删除第一行。

假设目录包含:file1.txt file2.txt file3.txt ...等

我正在使用 sed 命令(非 GNU):

sed -i -e "1d" *.txt

出于某种原因,这只是删除了第一个文件的第一行。我认为 *.txt 会影响目录中与模式匹配的所有文件。奇怪的是,它正在创建附加了 -e 的文件副本,但副本和原始文件是相同的。

我用其他命令(例如 ls *.txt)试过了,效果很好。我缺少有关 sed 的内容吗?

提前谢谢你。

  1. 在没有 -e 的情况下使用它!

一个文件使用:

sed -i '1d' filename

所有文件使用:

sed -i '1d' *.txt

files=/path/to/files/*.extension ; for var in $files ; do sed -i '1d' $var ; done

。对我来说,我使用 ubuntu 和基于 debian 的系统,这种方法对我 100% 有效,但对于其他平台我不确定,所以这是另一种方法:

  1. 用空模式替换第一行,并删除空行,(双命令):

    对于 $(ls /path/to/files/*.txt) 中的文件;做 sed -i "s/$(head -1 "$files")//g" "$files" ; sed -i '/^$/d' "$文件" ;完成

注意:如果您的文件包含启动符“/”,则会报错,因此在这种情况下,sed 命令应如下所示 (sed -i "s[$(head -1 "$files")[[g")

希望这就是您要找的:)

不同操作系统的不同版本sed支持不同的参数。

OpenBSD (5.4) sed

-i 标志不可用。您可以使用以下 /bin/sh 语法:

for i in *.txt
do
    f=`mktemp -p .` 
    sed -e "1d" "${i}" > "${f}" && mv -- "${f}" "${i}"
done

FreeBSD (11-CURRENT) sed

-i 标志需要扩展,即使它是空的。因此必须写成 sed -i "" -e "1d" *.txt

GNU sed

这会查看 -i 之后的参数是否是另一个选项(或者可能是一个命令)。如果是这样,它假定进行了就地修改。如果它看起来是文件扩展名,例如“.bak”,它会将原来的文件重命名为“.bak”,然后将其修改为原始文件的名称。

其他平台上可能还有其他变体,但我手头有这三个。

这里的问题是当 sed 打开一个新文件时,行号没有被重置,所以 1 只匹配第一个文件的第一行。

一个解决方案是使用 shell 循环,为每个文件调用一次 sed。 展示了如何以最广泛兼容的方式执行此操作,但如果您有支持 -i 标志的 sed 版本,则可以改为执行此操作:

for i in *.txt; do
    sed -i.bak '1d' "$i"
done

可以通过传递一个空后缀来避免创建备份文件,但我个人认为这不是一件坏事。总有一天你会感激的!


您似乎没有使用 GNU 工具,但如果您使用过,我建议您使用 GNU awk 来完成此任务。变量 FNR 在这里很有用,因为它单独跟踪每个文件的记录号,允许您这样做:

gawk -i inplace 'FNR>1' *.txt

使用 inplace 扩展,这允许您从每个文件中删除第一行,只打印 FNR 大于 1 的行。

正在测试:

$ seq 5 > file1
$ seq 5 > file2
$ gawk -i inplace 'FNR>1' file1 file2
$ cat file1
2
3
4
5
$ cat file2
2
3
4
5

你传递给 Sed 的最后一个参数是问题所在 尝试这样的事情。

var=(`find *txt`)
for file in "${var[@]}"
do
    sed -i -e 1d $file
done

这对我有用。