如何在 R 中将 awk 输出写入文件并动态传入文件路径?
结论
print > output.txt 中的文件名没有加双引号,导致 awk 无法按预期解析。固定文件名应写成 print > "output.txt";如果文件名保存在变量中,则写成 print > out。
在 R 中,可以让 awk 正常输出,再通过 system2(stdout = output_file) 将结果写入文件。这样可以减少 R 字符串和 awk 字符串之间的引号嵌套。
示例中的 data.txt 和 data.text 不一致,请先确认实际文件名。下面统一使用 data.txt。
推荐:使用 system2() 的 stdout 参数
input_file <- normalizePath(
"data.txt",
winslash = "/",
mustWork = TRUE
)
output_file <- file.path(getwd(), "output.txt")
awk <- unname(Sys.which("awk"))
if (!nzchar(awk)) {
stop("未在 PATH 中找到 awk,请检查安装位置。")
}
status <- system2(
command = awk,
args = c(
shQuote("/=/ { print }"),
shQuote(input_file)
),
stdout = output_file,
stderr = ""
)
if (status != 0L) {
stop(sprintf("awk 执行失败,退出状态为 %s。", status))
}
对于题目中的输入,output.txt 应包含:
lala=something
dada=somethingelse
各参数的作用是:
args中的 awk 程序和输入路径使用shQuote(),以处理命令行参数中的空格等字符。stdout直接接收 R 文件路径字符串,不需要再套shQuote()。stderr = ""让错误信息走标准错误输出,便于排查失败原因。
原代码使用 intern = TRUE 将标准输出捕获为 R 字符向量。这里直接将输出写入文件,不需要该参数。
如果希望由 awk 打开输出文件
可以通过 -v 把 R 字符串传给 awk 变量,避免把路径直接拼进 awk 程序:
# 沿用上面的 input_file、output_file 和 awk。
# 输出目录必须已经存在。
output_dir <- normalizePath(
dirname(output_file),
winslash = "/",
mustWork = TRUE
)
out_path <- file.path(output_dir, basename(output_file))
status <- system2(
command = awk,
args = c(
"-v",
shQuote(paste0("out=", out_path)),
shQuote("/=/ { print > out }"),
shQuote(input_file)
),
stderr = ""
)
if (status != 0L) {
stop(sprintf("awk 执行失败,退出状态为 %s。", status))
}
-v out=... 在处理输入前设置变量 out,print > out 使用该变量的值作为文件名。不要写成 print > "out",否则会写入一个名为 out 的文件。
Windows 路径建议先转换为 / 分隔形式,因为 awk 的 -v 赋值会解释反斜杠转义。对于包含字面反斜杠等特殊字符的路径,优先使用前面的 stdout 方案,减少路径经过 awk 解释的机会。
原代码为什么失败
下面的 awk 程序中,output.txt 不是字符串字面量,句点也不能这样用于文件名表达式:
/=/ { print > output.txt }
固定文件名在 awk 语法层面应写为:
/=/ { print > "output.txt" }
shQuote() 保护的是传给外部命令的参数,awk 程序内部的文件名仍需符合 awk 语法。仅给整段程序套上 shQuote(),不能修复其中缺失的字符串引号。
跨平台和文件行为
上述筛选表达式和 -v 用法适用于常见 awk 实现,但每台机器都需要有可执行的 awk,并确保命令路径正确。如果安装后的命令叫 gawk,请改用 Sys.which("gawk"),也可以直接指定可执行文件路径。
输出目录必须存在且可写。stdout = output_file 会创建或覆盖输出文件,即使没有匹配行,也会得到空文件。awk 内部的 print > out 只在实际执行到该语句时打开文件;如果没有匹配行,已有输出文件可能保持原样。
awk 的 > 在本次运行首次打开该文件时覆盖旧内容,后续匹配行继续写入同一文件。如需追加,应使用 >>。
备注:内容仅供参考。
