我想向多个文件添加包含空格的标题行。
这是我到目前为止所拥有的:
#!/bin/bash
# script name is "add_header.sh"
# ARG1 = HEADER STRING
# ARG2,3,... = ARRAY OF FILES TO ADD HEADER TO, RELATIVE DIRECTORY
HEADER=$1
shift
for FILE in $@; do
awk -v HEADER=$HEADER FILE=$FILE 'BEGIN{print HEADER} {print}' FILE > FILE.new
done
不幸的是,当我在我的用例上运行它时,由于空格而失败:
touch file1 file2 file3
./add_header.sh "some header with spaces" file1 file2 file3
这给出了以下错误:
awk: fatal: cannot open file `with' for reading (No such file or directory)
awk: fatal: cannot open file `with' for reading (No such file or directory)
awk: fatal: cannot open file `with' for reading (No such file or directory)
有没有办法转义 bash 变量中的空格?我尝试在每个空格之前使用 \ ,但错误现在更改为:
./add_header.sh "some\ header\ with\ spaces" file1 file2 file3
awk: fatal: cannot open file `with\' for reading (No such file or directory)
awk: fatal: cannot open file `with\' for reading (No such file or directory)
awk: fatal: cannot open file `with\' for reading (No such file or directory)
这意味着空格没有被转义。
答案1
#!/bin/sh
header=$1; shift
for pathname do
{ printf '%s\n' "$header"; cat -- "$pathname"; } >"$pathname.new"
done
这里没有真正的需要,awk
因为我们想要连接标头和旧文件内容。我们通过简单地输出标题字符串,printf
然后使用cat
来输出文件的内容来做到这一点。我们将printf
和的输出重定向cat
到一个新文件。
你会真的想要使用 来执行此操作awk
,则可以像上面的代码一样循环遍历文件,或者让awk
处理每个文件而不需要显式的 shell 循环。
第一个带有显式 shell 循环的变体:
#!/bin/sh
header=$1; shift
for pathname do
header=$header awk 'BEGIN { print ENVIRON["header"] }; 1' "$pathname" >"$pathname.new"
done
上述解决方案将是此答案中所有变体中最慢的变体,因为它awk
每个文件调用一次。
没有 shell 循环的第二种变体(需要像 GNU 那样awk
理解):BEGINFILE
awk
#!/bin/sh
header=$1; shift
header=$header awk '
BEGINFILE { fname = FILENAME ".new"; print ENVIRON["header"] >(fname) }
{ print >(fname) }' "$@"
第三种变体(最后一段代码的可移植变体):
#!/bin/sh
header=$1; shift
header=$header awk '
FNR == 1 { fname = FILENAME ".new"; print ENVIRON["header"] >(fname) }
{ print >(fname) }' "$@"
答案2
假设您没有空输入文件,正确的方法是:
#!/usr/bin/env bash
header=$1
shift
awk -v header="$header" '
FNR==1 { close(out); out=FILENAME ".new"; $0=header ORS $0 }
{ print > out }
' "$@"
上面的代码可以在每个 Unix 机器上的任何 shell 中使用任何 awk 来工作。如果您可以有空的输入文件,则需要进行调整。
答案3
这是对我有用的修改版本:
#!/bin/bash
header=$1
shift
for file in $@; do
awk -v HEADER="$header" 'BEGIN{print HEADER} {print}' "$file" > "$file".new
done
我尝试在 awk 表达式内部使用{print > [FILE].new}
,但它不起作用。它刚刚打印到stdout
.可能是因为 awk 中无法创建新文件。