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

时间:2015-05-25 23:04:44

标签: macos bash shell sed zsh

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

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

所以说该目录包含:file1.txt file2.txt file3.txt ... etc。

我使用的是sed命令(非GNU):

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

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

我尝试使用其他命令(例如ls * .txt),它运行正常。有什么关于sed我不知道了吗?

提前谢谢你。

4 个答案:

答案 0 :(得分:2)

  1. 使用它而不用-e!
  2. 用于一个文件:

    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. 用emty模式替换第一行,删除空行,(双命令):

      表示$(ls /path/to/files/*.txt)中的文件; do sed -i“s / $(head -1”$ files“)// g”“$ files”; sed -i'/ ^ $ / d'“$ files”;完成

    2. 注意:如果你的文件包含splash'/',那么它会给出错误,所以在这种情况下,sed命令应该如下所示(sed -i "s[$(head -1 "$files")[[g"

      希望这就是你要找的东西:)

答案 1 :(得分:2)

不同操作系统中不同版本的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"重命名原始文件。然后将其修改为原始文件的名称。

其他平台可能还有其他变体,但这些是我手边的三个。

答案 2 :(得分:0)

这里的问题是当sed打开一个新文件时不会重置行号,因此1只匹配第一个文件的第一行。

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

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

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

您似乎没有使用GNU工具,但如果您使用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

答案 3 :(得分:0)

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

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

这对我有用。