250

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

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

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

4

9 回答 9

214

我很惊讶没有人提到 find 的 -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'

或者更简单地使用+ exec 变体而不是;in find 以允许 find 为每个子进程调用提供多个文件:

find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} +
于 2015-06-08T19:46:05.800 回答
161

更好的是:

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)
#
于 2012-05-04T09:32:40.490 回答
87

您可以同时使用 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)
于 2014-03-20T13:41:21.107 回答
36

sed这些命令在Mac OS X 附带的默认设置中不起作用。

来自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

两者都工作正常。

于 2012-05-26T05:58:44.793 回答
22

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

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

这将适用于中等数量的文件,可能在几十个数量级,但可能不是在几百万个数量级

于 2015-01-23T23:23:57.727 回答
13

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

sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')
于 2015-01-08T21:34:52.490 回答
4

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

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

这样您就不必编写复杂的循环,而且很容易看到您要更改哪些文件,只需在运行find之前运行sed

于 2017-10-24T21:44:16.293 回答
0

你可以做

' xxxx ' 文本 u 搜索并将其替换为 ' yyyy '

grep -Rn '**xxxx**' /path | awk -F: '{print $1}' | xargs sed -i 's/**xxxx**/**yyyy**/'
于 2015-12-02T13:47:04.390 回答
0

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

使用字典/哈希映射(关联数组)和sed命令变量,我们可以循环遍历数组来替换几个字符串。在 中包含通配符将允许用特定目录 ( ) 中name_pattern的模式(这可能类似于 )替换文件中的文件。所有的变化都写在name_pattern='File*.txt'source_dirlogfiledestin_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

首先声明pairs数组,每对是一个替换字符串,然后在文件中WHAT1被替换为FOR1OTHER_string_to replace被替换。在循环中读取数组,该对的第一个成员被检索为,第二个成员被检索为。该命令在目录中搜索文件名(可能包含通配符),并且该命令在同一文件中替换先前定义的内容。最后,我添加了一个重定向到日志文件以记录文件中所做的更改。string replacedFile.txtreplace_what=$ireplace_for=$jfindsed -igrep

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

于 2018-09-18T21:33:05.250 回答