【问题标题】:awk print output to a directory using shell argument or shell variableawk 使用 shell 参数或 shell 变量将输出打印到目录
【发布时间】:2017-06-17 15:36:48
【问题描述】:

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

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

testshell.sh

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

awk 程序:

testawk

#!/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 变量以设置输出目录?

感谢帮助和任何示例方法

【问题讨论】:

  • 总而言之,您的问题是“如何在 awk 脚本中获取命令行参数?”和“如何在 awk 脚本中创建目录?”
  • 相当接近,“如何在 awk 脚本中获取命令行参数?”对于第二个问题“输出到现有目录,通过在 awk 脚本中的路径和命令行参数中明确说明”的两种情况,如果目录不存在,最好有一个创建目录的示例也是。
  • Here's 用于获取命令行参数的副本。您已经可以使用print "foo" > "dir/subdir/file" 写入存在的子目录中的文件
  • 最好这样ARGV[2]"/"fn。如果是重复的// 这不是问题。
  • 不,没问题。路径中的 Multilply / 将被系统忽略。

标签: bash shell awk text-processing


【解决方案1】:

使用 shebang 执行 awk 脚本只会让你的生活变得更艰难,不要这样做。如果你摆脱 shebang 并将“testawk”写为:

odir="$1"
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 with

system("mkdir -p \047" foo "\047")

【讨论】:

  • 谢谢,这看起来很优雅。如上所述实现,但收到错误“awk: cmd. line:3: (FILENAME=inputfile.txt FNR=1) fatal: can't redirect to odir=./ouputdir/outputfile1.txt (No such file or directory)
  • @Gabe 听起来您使用的是tstawk odir=./outputdir/ 而不是tstawk ./outputdir/"$@" 被 shell 扩展为 "$1" "$2" 等。是的,这正是你要写的。
  • 上例中的次要注释shelloutputdir="./ouputdir/" 在我的例子中是="./outputdir/" 可以看到使用ouputdir 优于outputdir
  • 干得好;值得注意的是,如果 foo 包含单引号,那么 system("mkdir -p \047" foo "\047") 将会中断,并且通用的 quoting-for-the-shell 机制需要更多的工作。
  • 感谢所有为此提供帮助的人。我现在已经在我的 [xml 提取和验证管道](stackoverflow.com/questions/44388628/…) 中实现了这个框架,并且对扩展这个代码库以扩展处理大型数据集的相对简单性感到非常满意。接下来是性能测量模块。
【解决方案2】:

注意:
* 此答案根据使用 shebang 行 (#!/usr/bin/awk -f) 的独立awk 脚本解决了所提出的问题。
* Ed Morton's helpful answer 展示了如何从 shell 脚本调用 awk 作为替代方案,这有其优势。

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

鉴于./outputdir/ 根据定义是一个目录,它不能作为输入文件,这就是您收到警告的原因。

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

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

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. 如何在 awk 中显式设置输出目录?

没有Awk-internal机制,但是你可以使用shellcd到输出目录beforehand

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

参见上面的解决方案。 Awk 中没有特殊的 output-directory 参数,但是您可以将 output-directory 路径作为 Awk variable 传递。

  1. 如果 awk 中不存在目录,我该如何创建?

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

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

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

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

\047 是一个表示' 的八进制转义序列,必须在从 shell 显式调用awk 时使用它,因为'...' 已经被用来包围整个脚本,防止使用嵌入 ' 字符。完全是因为单引号的 shell 字符串不支持它。

这是 独立 awk 脚本优于从 shell 显式调用 awk 的一个方面:您可以在独立脚本 - 不需要\047

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

查看问题 #2 的答案。

【讨论】:

  • 谢谢,这是一个非常有用且内容丰富的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-02
  • 1970-01-01
  • 2012-08-17
  • 2018-10-03
相关资源
最近更新 更多