更改多个文件

时间:2012-05-04 09:09:53

标签: sed

以下命令正确更改了2个文件的内容。

sed -i 's/abc/xyz/g' xaa1 xab1 

但我需要做的是动态更改几个这样的文件,我不知道文件名。我想编写一个命令来读取当前目录中以xa*开头的所有文件,而sed应该更改文件内容。

9 个答案:

答案 0 :(得分:125)

我很惊讶没有人提到查找的-exec参数,它适用于这种类型的用例,尽管它会为每个匹配的文件名启动一个进程:

find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} \;

或者,可以使用xargs,这将调用更少的进程:

find . -type f -name 'xa*' | xargs sed -i 's/asd/dsg/g'

或者更简单地在find中使用+ exec variant而不是;来允许find为每个子进程调用提供多个文件:

find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} +

答案 1 :(得分:119)

更好的是:

for i in xa*; do
    sed -i 's/asd/dfg/g' $i
done

因为没有人知道有多少文件,并且很容易打破命令行限制。

以下是文件太多时会发生的情况:

# grep -c aaa *
-bash: /bin/grep: Argument list too long
# for i in *; do grep -c aaa $i; done
0
... (output skipped)
#

答案 2 :(得分:76)

你可以一起使用grep和sed。这允许您递归搜索子目录。

Linux: grep -r -l <old> * | xargs sed -i 's/<old>/<new>/g'
OS X: grep -r -l <old> * | xargs sed -i '' 's/<old>/<new>/g'

For grep:
    -r recursively searches subdirectories 
    -l prints file names that contain matches
For sed:
    -i extension (Note: An argument needs to be provided on OS X)

答案 3 :(得分:28)

这些命令不适用于Mac OS X附带的默认sed

来自man 1 sed

-i extension
             Edit files in-place, saving backups with the specified
             extension.  If a zero-length extension is given, no backup 
             will be saved.  It is not recommended to give a zero-length
             extension when in-place editing files, as you risk corruption
             or partial content in situations where disk space is exhausted, etc.

尝试

sed -i '.bak' 's/old/new/g' logfile*

for i in logfile*; do sed -i '.bak' 's/old/new/g' $i; done

两者都很好。

答案 4 :(得分:14)

@PaulR将此作为评论发布,但人们应将其视为答案(此答案最适合我的需求):

sed -i 's/abc/xyz/g' xa*

这适用于适量的文件,可能大约为数十,但probably not on the order of millions

答案 5 :(得分:6)

另一种更通用的方法是使用find

sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')

答案 6 :(得分:1)

我使用find执行类似的任务。这很简单:你必须将它作为sed的参数传递给你:

sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`

通过这种方式,您不必编写复杂的循环,很容易看到,您要更改哪些文件,只需在运行find之前运行sed

答案 7 :(得分:0)

你可以做

&#39;的 XXXX &#39;发短信给你搜索并将其替换为&#39; yyyy &#39;

grep -Rn '**xxxx**' /path | awk -F: '{print $1}' | xargs sed -i 's/**xxxx**/**yyyy**/'

答案 8 :(得分:0)

如果您能够运行脚本,这是我在类似情况下所做的事情:

sed命令使用字典/ hashMap(关联数组)和变量,我们可以遍历数组以替换多个字符串。在name_pattern中包含通配符将允许使用特定目录(name_pattern='File*.txt')中的模式(这可能类似于source_dir)替换文件中的位。 所有更改都写在logfile的{​​{1}}

destin_dir

首先,声明对数组,每个对都是替换字符串,然后在#!/bin/bash source_dir=source_path destin_dir=destin_path logfile='sedOutput.txt' name_pattern='File.txt' echo "--Begin $(date)--" | tee -a $destin_dir/$logfile echo "Source_DIR=$source_dir destin_DIR=$destin_dir " declare -A pairs=( ['WHAT1']='FOR1' ['OTHER_string_to replace']='string replaced' ) for i in "${!pairs[@]}"; do j=${pairs[$i]} echo "[$i]=$j" replace_what=$i replace_for=$j echo " " echo "Replace: $replace_what for: $replace_for" find $source_dir -name $name_pattern | xargs sed -i "s/$replace_what/$replace_for/g" find $source_dir -name $name_pattern | xargs -I{} grep -n "$replace_for" {} /dev/null | tee -a $destin_dir/$logfile done echo " " echo "----End $(date)---" | tee -a $destin_dir/$logfile 中将WHAT1替换为FOR1,并将OTHER_string_to replace替换为string replaced。文件File.txt。在循环中,读取数组,该对的第一个成员检索为replace_what=$i,第二个成员检索为replace_for=$jfind命令在目录中搜索文件名(可能包含通配符),而sed -i命令将替换先前定义的文件。最后,我添加了一个grep重定向到日志文件,以记录在文件中所做的更改。

这在GNU Bash 4.3 sed 4.2.2中对我有用,并且基于VasyaNovikov对Loop over tuples in bash的回答。