我有许多.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
意思是:编辑文件i
n-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
并打印。