我正在尝试将此命令复制到 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”不存在
。我认为上面会在解析时创建文件。任何帮助,将不胜感激。
最佳答案
您很可能已成为 Windows PowerShell 对 Get-ChildItem
输出的 System.IO.FileInfo
实例的不一致字符串化的受害者 - 请参阅 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
默认情况下那样)直接应用于生成的多行字符串并替换所有出现的地方。-NoNewline
(PSv5+) 确保Set-Content
不会在多行字符串中添加额外尾随换行符已保存(同样适用于Out-File
/>
)。注意:鉴于
Get-Content -Raw
预先读取整个文件,您甚至可以将修改后的内容写回同一个文件,而无需中间临时文件和随后的Move-Item
调用;也就是说,如果写回同一文件的过程被中断,这样做会带来轻微的数据丢失风险。- 此外,虽然您的
sed
调用会保留扩展名为.bak
的原始文件,但您的 PowerShell 命令不会。
- 此外,虽然您的
关于bash - 查询 | sed -i 相当于 Windows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55154079/