【发布时间】:2010-10-17 21:16:13
【问题描述】:
文件最初是
$cat so/app.yaml
application: SO
...
我运行以下命令。我得到一个空文件。
$sed s/SO/so/ so/app.yaml > so/app.yaml
$cat so/app.yaml
$
如何使用 SED 编辑文件而不给我一个空文件?
【问题讨论】:
标签: sed
文件最初是
$cat so/app.yaml
application: SO
...
我运行以下命令。我得到一个空文件。
$sed s/SO/so/ so/app.yaml > so/app.yaml
$cat so/app.yaml
$
如何使用 SED 编辑文件而不给我一个空文件?
【问题讨论】:
标签: sed
$ sed -i -e's/SO/so/' so/app.yaml
-i 表示就地。
【讨论】:
sed 版本可能不支持-i - 例如,在Solaris 中。在这种情况下,通常会有一个gsed 支持它。
-i 在 AIX 系统上不受支持。解决方法是将其输出到一个 tmp 文件,然后将其复制到您要修改的文件中。
我认为将输出重定向到您正在编辑的同一文件会导致您的问题。
您需要将标准输出重定向到某个临时文件,并在 sed 完成后用临时文件覆盖原始文件。
【讨论】:
管道中使用的> 将在管道全部设置好后(即在命令执行之前)打开输出文件。因此,输入文件在sed 执行之前被截断。这是所有 shell 重定向的问题,而不仅仅是 sed。
Sheldon Young 的回答展示了如何使用就地编辑。
【讨论】:
sed s/ABC/abc/ settings.py> settings.py.
> 的使用是将其输出到一个tmp 文件,然后将其复制回来。 sed s/ABC/abc/ settings.py > tmp; cp tmp settings.py
您为这项工作使用了错误的工具。 sed 是一个 stream 编辑器(这就是它被称为 sed 的原因),因此它用于对管道中的流进行动态编辑。 ed OTOH 是一个 file 编辑器,它可以做sed 可以做的所有事情,除了它适用于文件而不是流。 (实际上,恰恰相反:ed 是原始实用程序,sed 是一个克隆,可以避免为流创建临时文件。)
ed 的工作方式与sed 非常相似(因为sed 只是一个克隆),但有一个重要区别:您可以在文件中移动,但不能在流中移动。因此,ed 中的所有命令都带有一个地址参数,该参数告诉 ed, where 在文件中应用该命令。在您的情况下,您希望在文件中应用命令 everywhere,因此地址参数只是 ,,因为 a,b 表示“从行 a 到行 b”和a 的默认值为 1(文件开头),b 的默认值为 $(文件结尾),因此将它们都排除在外意味着“从文件开头到结尾文件”。然后是s(替代),其余的看起来很像sed。
所以,你的sed 命令s/SO/so/ 变成了ed 命令,s/SO/so/。
而且,由于ed 是一个文件编辑器,更准确地说是一个交互式文件编辑器,我们还需要编写 (w) 文件并退出 (q) 编辑器。
这是它的整体外观:
ed -- so/app.yaml <<-HERE
,s/SO/so/
w
q
HERE
关于类似问题,另请参阅 my answer。
在您的情况下,执行管道是一个两阶段的过程:首先构建管道,然后运行它。 > 表示“打开文件,截断它,并将其连接到文件描述符 1 (stdout)”。 只有这样才是真正运行的管道,即执行了sed,但是此时文件已经被截断了。
sed 的某些版本还有一个 -i 参数用于文件的就地编辑,这使得 sed 的行为更像 ed,但不建议使用它:首先,它不支持ed 的所有功能,但更重要的是,它是GNU sed 的非标准化专有扩展,不适用于许多非GNU 系统。我已经有一段时间没有使用非 GNU 系统了,但上次我使用了一个,Solaris、OpenBSD、HP-UX 和 IBM AIX sed 都不支持 -i 参数。
【讨论】: