awk 使用 shell 参数或 shell 变量将输出打印到目录

awk print output to a directory using shell argument or shell variable

如何使用 shell 参数或命令参数将输出打印到 awk 中的目录?

Shell 程序调用并将参数传递给 awk 程序:

testshell.sh

shelloutputdir="./ouputdir/"
./testawk inputfile.txt ./outputdir/

awk 程序:

测试

#!/usr/bin/awk -f
{
    print FILENAME > "./outputdir/outputfile1.txt"
    fn2="outputfile2.txt"
    fn3="outputfile3.txt"
    fn4="outputfile4.txt"
    print FILENAME > ARGV[2]"/"fn2
    print FILENAME > ARGV[2]"subdir/"fn3
    print FILENAME > $shelloutputdir"subdir/"fn4
}

注:

inputfile.txt

只是一个示例,因为 shell 和 awk 程序将处理其他参数。

输出目录已经存在。

./outputdir/
./outputdir/subdir/

输出:

./outputdir/outputfile1.txt
./outputdir/outputfile2.txt
./outputdir/subdir/outputfile3.txt

outputfile4.txt 未创建

错误:

awk: ./testawk:9: (FILENAME=inputfile.txt FNR=1) fatal: can't redirect to `input text filesubdir/outputfile4.txt' (No such file or directory)

问题汇总:

  1. 如何在 awk 中显式设置输出目录?

  2. 如何使用命令行参数在awk中设置输出目录?

  3. awk中不存在的目录如何创建?

  4. 如何将 shell 变量传递给 awk 变量以设置输出目录?

感谢帮助和任何示例方法

注:
* 此答案基于使用 shebang 行 独立 awk 脚本#!/usr/bin/awk -f).
* 展示了如何从 shell 脚本 调用 awk 作为替代方法,这有其优点。

script 操作数 之后传递给 awk 的所有操作数(这隐含地是独立脚本本身, 在这种情况下) 默认解释为 输入文件.

鉴于 ./outputdir/ 根据定义是一个 目录 ,它不能充当输入 文件 ,它是为什么你会收到警告。

但是,Awk 提供 伪文件名操作数语法 <var>=<value>,而不是传递 filename, 定义了一个Awk variable,类似于pre-script -v <var>=<value> option 语法(假设您的调用是通过 shebang 行进行的,基于 -v 选项的变量赋值是 not一个选项)。

请注意,这些 赋值是在 post 脚本操作数列表中遇到 时发生的,因此您需要 放置它们 处理依赖于它们的实际输入文件之前:

shelloutputdir="./outputdir/"
./testawk odir="$shelloutputdir" inputfile.txt # Note the definition of variable `odir`

您可以通过这种方式定义的变量数量没有限制,但是,至少在假设上,您受到命令行最大总长度的限制,该值接近,但少于 getconf ARG_MAX 报告的内容。

上面定义了 Awk 变量 odir,因此您的脚本需要引用它:

#!/usr/bin/awk -f
{
    fn3="outputfile3.txt"
    print FILENAME > (odir "subdir/" fn3)
}

正如Ed Morton指出的那样,如果输出文件名是根据表达式计算得出的,那么表达式应该包含在(...) 用于稳健性;虽然它在 某些 Awk 实现(例如 GNU Awk 和 Mawk)中也可以在没有括号的情况下工作,但它会在其他实现中中断(例如 BSD/macOS Awk)。
Awk POSIX spec 不规范这种情况下的行为。


  1. How do I explicitly set the output directory in awk?

没有 Awk 内部机制,但您可以使用 shellcd 到输出目录 之前.

  1. How do I use a command line parameter to set the output directory in awk?

参见上面的解决方案。 Awk 中没有特殊的输出目录参数,但您可以将输出目录路径作为 Awk 变量.

传递
  1. How do I create a directory if it does not exist in awk?

没有 Awk 内部机制,但是 - 如果创建目录。在 shell 中提前不是一个选项 - 您可以使用 system() 函数来调用 mkdir;例如:

# If the dir. name never contains ' (single quotes):
awk -v odir="out-dir" 'BEGIN { system("mkdir 7" odir "7") }'

# *From inside your stand-alone Awk script only*, you don't need 7 to represent
# ' chars - see below.
system("mkdir '" odir "'")

# Otherwise, more work is needed:
awk -v odir="out'dir" '
   function shellQuote(s) { gsub("7", "7\77", s); return "7" s "7" }
   BEGIN { system("mkdir " shellQuote(odir)) }
'

7是表示'的八进制转义序列,必须在显式调用awk时使用,从shell,因为 '...' 已经被用来将 脚本作为一个整体包含起来 ,这会阻止使用 embedded ' 字符。完全一样,因为单引号 shell 字符串不支持它。

这是 独立 awk 脚本优于来自 shell 的显式 awk 调用的一个方面:您可以在独立脚本中自由使用文字 ' 实例 - 不需要 7.

  1. How do I pass a shell variable to an awk variable to set the output directory?

查看问题 #2 的答案。

使用 shebang 执行 awk 脚本只会让你的生活更艰难,不要这样做。如果去掉 shebang 并将 "testawk" 写为:

odir=""
shift
/usr/bin/awk -v odir="$odir" '
{
    print FILENAME > (odir "outputfile1.txt")
    fn2="outputfile2.txt"
    fn3="outputfile3.txt"
    fn4="outputfile4.txt"
    print FILENAME > (odir fn2)
    print FILENAME > (odir "subdir/" fn3)
    print FILENAME > (odir "subdir/" fn4)
}
' "$@"

那么你可以这样称呼它:

shelloutputdir="./outputdir/"
./testawk "$shelloutputdir" inputfile.txt

或者做任何你喜欢的事。关键是,不使用 shebang 可以让您将 awk 与 shell args 和 awk 文件名与 awk 变量初始值分开。

您可以创建一个目录,其名称存储变量 foo

system("mkdir -p 7" foo "7")