ChatGPT解决这个技术问题 Extra ChatGPT

在 OS X 上使用 sed 就地编辑

我想在 OS X 上使用 sed 编辑文件。我正在使用以下命令:

sed 's/oldword/newword/' file.txt

输出被发送到终端。 file.txt 没有被修改。使用以下命令将更改保存到 file2.txt:

sed 's/oldword/newword/' file1.txt > file2.txt

但是我不想要另一个文件。我只想编辑file1.txt。我怎样才能做到这一点?

我试过 -i 标志。这会导致以下错误:

sed: 1: "file1.txt": invalid command code f
当您尝试使用 -i 标志时,您使用的确切命令是什么?

E
Eduardo Cuomo

您可以正确使用 -i 标志,方法是为其提供一个后缀以添加到备份文件中。扩展您的示例:

sed -i.bu 's/oldword/newword/' file1.txt

将为您提供两个文件:一个名称为 file1.txt 包含替换,另一个名称为 file1.txt.bu 包含原始内容。

轻度危险

如果您想破坏性地覆盖原始文件,请使用以下内容:

sed -i '' 's/oldword/newword/' file1.txt
      ^ note the space

由于解析行的方式,选项标志和它的参数之间需要一个空格,因为参数是零长度的。

除了可能破坏您的原件外,我不知道以这种方式欺骗 sed 有任何进一步的危险。然而,应该注意的是,如果 sed 的调用是脚本的一部分,那么 Unix Way™ 将(恕我直言)非破坏性地使用 sed,测试它是否干净地退出,然后才删除无关文件。


没错,我在 -i 标志之后省略了扩展名。除了可能弄乱原始文件(并且没有备份)之外,-i'' 是否有危险?
根据 sed 手册页,如果设备上的磁盘空间不足,您可能会在中途损坏文件并产生错误的输出结果。如果您在本地源代码控制下工作,则 sed -i "" 没有备份大部分时间应该没问题(或者只是在 -i 模式下运行 sed 之前的 git init && git add -A . && git commit -m 'backup')。
我发现轻度危险的位特别有用。 +1
BSD sed 要求 -i 标志后没有空格。因此,-i'' 有效,但 -i '' 无效。
啊! BSD sed 忽略 '\n' 字符并打印 'n' 代替!我只是要在我的 mac 上用 GNU sed 替换 BSD sed!
k
ksnt

我对 MacOS 有类似的问题

sed -i '' 's/oldword/newword/' file1.txt

不起作用,但是

sed -i"any_symbol" 's/oldword/newword/' file1.txt

效果很好。


现在情况正好相反。 sed -i '' <file> 有效,但 sed -i'' <file> 不再有效
J
Jakub Kukul

-i 标志可能对您不起作用,因为您遵循了 GNU sed 的示例,而 macOS 使用 BSD sed 并且它们的语法略有不同。

所有其他答案都告诉您如何更正语法以使用 BSD sed。另一种方法是在您的 macOS 上安装 GNU sed:

brew install gsed

然后使用它代替 macOS 附带的 sed 版本(注意 g 前缀),例如:

gsed -i 's/oldword/newword/' file1.txt

如果您希望 GNU sed 命令始终可移植到您的 macOS,您可以在您的路径前添加“gnubin”目录,方法是在您的 .bashrc/.zshrc 文件中添加类似这样的内容(运行 brew info gsed 以查看您的具体内容需要做):

export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"

从那时起,GNU sed 成为您的默认 sed,您可以简单地运行:

sed -i 's/oldword/newword/' file1.txt

r
rink.attendant.6
sed -i -- "s/https/http/g" file.txt

当我在 mac 上尝试时,我收到一条错误消息,提示“sed: -i may not be used with stdin”。
在我的 macOS (10.15.6) 上,-- 似乎可以工作,但实际上它会创建一个 file.txt-- 备份文件,然后必须手动删除该文件,因此此解决方案并不比公认的解决方案更好。并且 -- 具有误导性,就好像该选项的行为就像 GNU 工具一样,以不同的方式对待它。
k
kenorb

您可以按照前面的建议将 -i'' (--in-place) 用于 sed。请参阅:The -i in-place argument,但请注意,-i 选项是非标准 FreeBSD 扩展,可能在其他操作系统上不可用。其次sed is a Stream EDitor, not a file editor

另一种方法是在 Vim Ex 模式下使用内置替换,例如:

$ ex +%s/foo/bar/g -scwq file.txt

对于多个文件:

$ ex +'bufdo!%s/foo/bar/g' -scxa *.*

要递归编辑所有文件,如果 shell 支持,您可以使用 **/*.*(由 shopt -s globstar 启用)。

另一种方法是使用 gawk 及其新的 "inplace" extension,例如:

$ gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' file1

J
JustADude

这将创建备份文件。例如 sed -i -e 's/hello/hello world/' testfile 对我来说,在同一个目录中创建一个备份文件 testfile-e。


Mac OS Catalina 也一样。分别传递 -i 和 -e (而不是一起传递 -ie!)会创建一个附加了“-e”的备份文件。
E
Eduardo Cuomo

您可以使用:

sed -i -e 's/<string-to-find>/<string-to-replace>/' <your-file-path>

例子:

sed -i -e 's/Hello/Bye/' file.txt

这在 Mac 中完美无缺。


这会在 Mac OS Catalina 中为我创建一个带有“-e”的备份文件。
这对 macOS 来说是错误的。请查看那里的“man sed”页面。 -i 需要 macOS 的参数。由于您没有指定一个,因此它使用 -e,这会导致第二个文件附加了 -e-e 在 macOS 中不存在,它是 -E。所以 macOS 的正确命令是 sed -i '' -E 's/Hello/Bye/' file.txt