【问题标题】:Write a shell script that replaces multiple strings in multiple files编写一个shell脚本,替换多个文件中的多个字符串
【发布时间】:2015-05-08 16:47:44
【问题描述】:

我需要在目录中的许多文件中搜索关键字列表并为所有文件添加前缀。例如,如果我的目录中的各种文件包含术语 foobarbaz,我将需要更改这些术语的所有实例到:prefix_fooprefix_barprefix_baz

我想编写一个 shell 脚本来执行此操作,这样我就可以避免在 SublimeText 中一次搜索一个关键字(它们有很多)。不幸的是,我的shell-fu没有那么强。

到目前为止,按照this 的建议,我创建了一个名为“replace.sed”的文件,其中所有术语的格式如下:

s/foo/prefix_foo/g
s/bar/prefix_bar/g
s/baz/prefix_baz/g

它建议与此列表一起使用的终端命令是:

sed -f replace.sed < old.txt > new.txt

我可以通过设置以下脚本(我称之为 inline.sh)来调整它以替换文件中的实例(而不是创建新文件):

#!/bin/sh -e
in=${1?No input file specified}
mv $in ${bak=.$in.bak}
shift
"$@" < $bak > $in

综合起来,我得到了这个命令:

~/inline.sh old.txt sed -f replace.sed

我试过了,它可以一次处理一个文件。我将如何调整它以搜索和替换整个目录中的所有文件?

【问题讨论】:

  • 通过shellcheck.net 运行您的脚本并修复它标记的问题——我的答案对于带有空格等的文件名是安全的,但您的inline.sh 目前是不是 i> 在这方面是安全的。

标签: macos shell sed terminal


【解决方案1】:
for f in *; do
  [[ -f "$f" ]] && ~/inline.sh "$f" sed -f ~/replace.sed
done

【讨论】:

  • 现在,我将如何进行递归?
  • @unifactor,什么版本的 bash?如果是 4.0 或更新版本,shopt -s globstar 然后使用for f in **/*
  • ...如果比这更早,那么find . -type f -exec ~/inline.sh '{}' sed -f ~/replace.sed ';'
【解决方案2】:

在脚本中:

#!/bin/bash
files=`ls -1 your_directory | egrep keyword`

for i in ${files[@]}; do
    cp ${i} prefix_${i}
done

当然,这会将原件留在原处。

【讨论】:

  • ...另外,您在扩展时使用数组语法(不正确,因为缺少引号),但您实际上并没有将 files 定义为数组(这就是为什么 添加引号而不修复files被定义为实际上是一个数组的方式会破坏事情)。
  • files=( your_directory/*keyword* ) 将是数组赋值等价物,顺便说一句,此后 for i in "${files[@]}"; do cp "$i" "prefix_$i"; done${i} 中的花括号对此处的正确性没有任何影响——人们可以在这个特定的用例中使用或保留它们——但缺少引号实际上对也可以解释为 glob 表达式的文件名有害或包含 IFS 中的字符。
猜你喜欢
  • 2018-09-26
  • 2019-01-07
  • 2017-08-01
  • 2012-10-24
  • 2016-04-26
  • 2010-10-13
  • 1970-01-01
相关资源
最近更新 更多