如何在 sed 命令中使用文件名?

如何在 sed 命令中使用文件名?

我有许多.conf文件,它们完全相同,并且位于同一个目录中,只是文件名不同。在每个唯一命名的.conf文件中,我想用文件的名称替换文件中的一组字符。例如:

目前在所有文件中:

datafname = example.nex
ofprefix = best.example

理想输出:

文件名:25.conf

datafname = 25.nex
ofprefix = best.25

文件名:26.conf

datafname = 26.nex
ofprefix = best.26

我认为我可以用来sed遍历所有这些文件来查找并用文件名替换文本字符串,方法如下:

sed -i conf 's/example/echo $f/g' *

但这样无法正常工作。有人能给出建议吗?

答案1

你可以做:

for f in *.conf; do
    base=$(basename "$f" '.conf') # gives '25' from '25.conf'
    sed -i.before "s/example/$base/g" "$f"
done

当使用-i开关时sed,您必须绝对确保您的sed命令有效,因为-i更改文件到位。这意味着生成的输出将覆盖输入文件。如果您的替换命令(s/…/…/)错误,您可能会得到空文件并且没有备份。因此,我使用了-i.before将保留*.before原始内容的文件。

答案2

您可以使用 for 循环来迭代文件。使用参数扩展来删除文件扩展名。使用双引号括住表达式,否则变量将不会扩展。

#! /bin/bash
for f in *.conf ; do
    b=${f%.conf}
    sed -i "s/example/$b/" "$f"
done

答案3

你可以使用 GNU 无需循环即可完成任务parallel 平行安装

parallel sed -i.old s/example/{.}/ {} ::: *.conf

如果你有很多要编辑的文件数,因为parallel每个 CPU 核心运行一个作业。

  • -i.old意思是:编辑文件in-place 并进行备份,将.old扩展名添加到原始文件名(.old如果不想备份,请删除,但请记住您没有备份)
  • s/example/{.}/g意味着用不带扩展名的输入文件名s进行替换( )并全局执行(=对每个出现的情况)example{.}g
  • {}替换为输入文件名
  • :::将要运行的命令与要传递给它的参数分开
  • *.conf匹配.conf当前目录下的每个文件

答案4

使用 awk,它会FILENAME自动将变量设置为文件名(如果是 GNU awk,还会进行就地编辑):

$ for i in {20..26}; do printf "%s\n" "datafname = example.nex" "ofprefix = best.example" > $i.conf; done
$ gawk -i inplace 'FNR == 1 {split(FILENAME, file, ".")} {gsub("example", file[1])} 1' *.conf
$ cat 25.conf
datafname = 25.nex
ofprefix = best.25
  • FNR == 1 {split(FILENAME, file, ".")}:在每个文件的第一行,拆分文件名.并将其存储在file数组中
  • {gsub("example", file[1])} 1:对于所有行,替换example为数组的第一个元素file并打印。

相关内容