我正在尝试将此命令复制到PowerShell:
grep -lR 'Find' ./src | while read filename; do sed -i".bak" 's/Find/Replace/g' "$filename"; done
到目前为止我所拥有的:
Get-ChildItem "src" -Recurse -File | ForEach-Object { $f = $_; (Get-Content $f) | ForEach-Object { $_ -replace "Find", "Replace" } | Set-Content "$f.tmp"; Move-Item "$f.tmp" $f -Force }
我遇到一个错误,说"filename.tmp" does not exist
。我认为以上将在解析时创建文件。任何帮助,将不胜感激。
答案 0 :(得分:1)
您很可能已成为Windows PowerShell对System.IO.FileInfo
输出的Get-ChildItem
实例的不一致字符串化的牺牲品-请参见this answer。
解决方法是通过.FullName
属性使用显式字符串化,该属性显式返回项目的完整路径。
已应用于您的命令,并进行了一些优化:
Get-ChildItem -File -Recurse src | ForEach-Object {
$f = $_.FullName # !! Explicitly retrieve the full path
(Get-Content $f -Raw) -creplace 'Find', 'Replace' |
Set-Content -NoNewline "$f.tmp"
Move-Item "$f.tmp" $f -Force
}
Get-Content -Raw
将整个文件作为单个字符串读入内存,这效率更高。
-creplace
(执行区分大小写的替换,默认情况下将执行sed
)直接应用于生成的多行字符串并替换所有出现的字符串。 / p>
-NoNewline
(PSv5 +)确保Set-Content
不会在要保存的多行字符串中添加 additional 尾随换行符(对{{1 }} / Out-File
)。
注意:假设>
预先读取了整个文件,您甚至可以将修改后的内容写回到同一文件中,而无需中间临时文件和后续的Get-Content -Raw
呼叫;也就是说,如果写回同一文件的过程被中断,这样做会带来轻微的数据丢失风险。
Move-Item
调用保留扩展名为sed
的原始文件,但您的PowerShell命令却没有。