【问题标题】:Using AWK to read line from file and create a variable使用 AWK 从文件中读取行并创建变量
【发布时间】:2012-04-16 20:26:54
【问题描述】:

我有一个包含文件名列表的文本文件。我想使用 AWK 从特定的行号创建一个变量。我得到正确的输出使用:

awk "NR==\$Line" /myPath/fileList.txt

我想将此输出分配给一个变量,并且从文档中我发现我希望以下工作:

INFILE=$(awk "NR==\$Line" /myPath/fileList.txt)

INFILE=`awk "NR==\$Line" /myPath/fileList.txt`

然而,

echo "\$INFILE" 

为空白。我是 bash 脚本的新手,不胜感激。

【问题讨论】:

  • 这些命令都不应该提供任何输出,它们设置了变量 INFILE。 (第一个版本“更好”。)
  • 对不起,我应该澄清一下。 echo "\$INFILE" 为空。
  • 如果您对美元符号进行转义,则不会扩展 INFILE 变量。请改用echo "$INFILE"
  • @ghoti:当我通过硬编码行号来测试这一点时,我发现转义是必要的。我认为这是因为我将脚本提交给作业调度程序。
  • echo "\$INFILE" 绝对不是空白。这意味着回显字符$INFILE,字面意思是:美元符号,后跟INFILE

标签: bash awk sungridengine command-substitution


【解决方案1】:

AWK 命令的输出分配给变量。要查看变量的内容,请执行以下操作:

echo "$INFILE"

您应该为您的 AWK 命令使用单引号,这样您就不必转义文字美元符号(文字字符串应该被引用,如果您想替换一个 shell 变量,请参见下文):

awk 'NR == "$Line"' /myPath/fileList.txt

$() 形式比反引号形式更受欢迎(顺便说一句,我不明白您为什么要转义反引号)。此外,您应该习惯性地使用小写或混合大小写的变量名,以避免与 shell 或环境变量的名称冲突。

infile=$(awk 'NR == "$Line"' /myPath/fileList.txt)
echo "$infile"

如果您的意图是替换名为 $Line 的变量的值,而不是使用文字字符串“$Line”,那么您应该使用 AWK 的 -v 变量传递功能:

infile=$(awk -v "line=$Line" 'NR == line' /myPath/fileList.txt)

【讨论】:

  • $line 变量是我的作业调度程序 SGE 设置的环境变量。我相信我需要在提交脚本中转义变量名。我尝试了 infile=$(awk -v "line=$SGE_TASK_ID" 'NR == line' /myPath/fileList.txt) 但从 echo $infile 得到了相同的结果。
  • @Sara:那么我的最后一个例子可能就是要走的路。然后你当然可以echo "$infile" 或以其他方式使用该变量。
  • 谢谢,你的例子很有意义,看起来应该可以工作,但是在遵循它之后,我仍然从 echo "$infile" 得到相同的空白结果。
  • 丹尼斯威廉姆森的例子应该(并且确实)输出abc;假设您已将 SGE_TASK_ID 设置为合适的值,例如。 SGE_TASK_ID=1; echo abc >file; infile=$(awk -v "line=$SGE_TASK_ID" 'NR == line' file); echo "$infile"
  • 感谢您的验证。我怀疑我还有一些其他问题,因为我无法复制这些结果。我认为有趣的是,在使用 echo 时我需要同时转义我的变量和环境变量。我想知道作业调度程序是否会导致这种行为,尽管我在文档中找不到。任何想法或建议将不胜感激。
【解决方案2】:

不要掩盖美元符号。

错误:

 echo "\$INFILE" 

右:

 echo $INFILE
 echo ${INFILE}
 echo "$INFILE"
 echo "${INFILE}"

如果您想将文本粘合在一起,${x} - 构造很有用。

 echo $INFILE0

将查找变量 INFILE0。如果 $INFILE 为 5,则不会产生“50”。

 echo ${INFILE}0

如果 INFILE 为 5,这将产生 50。

如果变量包含空格和或多或少不可预测的文本,撇号很有用。

如果你的行号是参数:

#!/bin/bash
Line=$1
INFILE=$(awk "NR==$Line" ./demo.txt)
echo "$INFILE"

如果 INFILE 包含多个空格或制表符,则 echo $INFILE 会将它们压缩为单个空格,而 "$INFILE" 会保留它们。

【讨论】:

  • 不,那不会产生十次 INFILE。它将产生INFILE,其后带有“0”。在这种情况下,大括号不用于参数扩展和大括号扩展 - 仅用于前者。你可以做INFILE=foo; echo "${INFILE}"{0..9},它会输出foo0 foo1 foo2 foo3 foo4 foo5 foo6 foo7 foo8 foo9。顺便说一句,您应该总是引用变量作为输出。这些不是撇号(单引号),它们是双引号。
  • 我可以通过硬编码行号来实现它:infile=$(awk "NR==1" /myPath/fileList.txt)。但我只能使用 echo \$infile 查看值。 echo $infile 为空白。我仍在努力理解为什么会这样。
  • @DennisWilliamson:如果 INFILE 为 7,它将产生 70,这就是我的意思。但是我的第一印象,一行的内容是一个数字,是错误的,虽然我最终意识到了这一点,但我在写的时候被打断了,忘记调整第一个例子。我不同意“你应该总是……”——那是货物崇拜节目。
  • @Sara:你想回显命令,还是命令的结果?我更新了我的答案以澄清丹尼斯的问题(用10 times 解释真的很糟糕),还添加了一个简短的变体,它采用 $LINE 的参数。请注意,$LINE 在我的示例中也没有被屏蔽,但也许我完全误会了您。
  • 我尝试从 $() 内部回显命令以查看它是如何被评估的。该变量在没有转义的情况下是未定义的,并且在转义后看起来是正确的。我认为这是因为我正在通过作业调度程序提交我的脚本。由于使用 echo 命令看起来是正确的,我不确定为什么当我将它放在 $() 中时它没有被正确评估。
猜你喜欢
  • 1970-01-01
  • 2018-04-25
  • 2019-09-18
  • 2014-10-15
  • 2017-01-24
  • 2020-12-30
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
相关资源
最近更新 更多