试图运行存储在文件中的几个awk命令

时间:2017-02-24 10:08:18

标签: bash shell

我有一个包含以下命令的文件

cat /some/dir/with/files/file1_name.tsv|awk -F "\\t" '{print $21$19$23$15}'
cat /some/dir/with/files/file2_name.tsv|awk -F "\\t" '{print $2$13$3$15}'
cat /some/dir/with/files/file3_name.tsv|awk -F "\\t" '{print $22$19$3$15}'

当我遍历文件以运行命令时,我得到以下错误

cat file | while read line; do $line; done
cat: invalid option -- 'F'
Try `cat --help' for more information.

2 个答案:

答案 0 :(得分:1)

您没有按预期正确执行命令。由于您在文件上逐行阅读(原因不明),您可以直接调用解释器,如下所示

#!/bin/bash
#      ^^^^ for running under 'bash' shell

while IFS= read -r line
do
    printf "%s" "$line" | bash
done <file

但这会产生为文件的每一行创建一个新进程的开销。如果file下的命令无害并且可以一次性运行,那么就可以

bash file

并完成它。

另外,对于使用awk,只需对每一行执行以下操作,以避免无用cat

awk -F "\\t" '{print $21$19$23$15}' file1_name.tsv

答案 1 :(得分:0)

您期望管道(|)符号按照您习惯的方式行事,但它并不适用。为了帮助您理解,请尝试以下方法:

A="ls / | grep e" # Loads a variable with a command with pipe
$A                # Does not work
eval "$A"         # Works

在不使用eval的情况下展开变量时,在shell解释重定向和管道之后会发生扩展和单词拆分,因此管道符号只能作为文字字符显示。

您有一些选择:

A)通过将文件名作为参数传递来避免管道

awk -F "\\t" '{print $21$19$23$15}' /some/dir/with/files/file1_name.tsv

B)如下所示使用eval,我建议您研究潜在的安全隐患。

C)将参数放入file并解析它,避免使用eval,例如:

# Assumes arguments separated by spaces
IFS=" " read -r -a arguments;
awk "${arguments[@]-}"

D)使用Bash而不是awk实现数据文件的解析,并使用配置文件指定输出而无需扩展任何内容(例如,通过指定要打印的字段)用空格分隔。)

前三种方法涉及某种形式的外部数据解释为代码,如果用作输入的文件不能保证安全,则会带来风险。在这方面,方法C可能被认为更好一些,但由于您调用的命令是awk,因此实际程序将传递给awk,因此无论awk能做什么,攻击者都可以(或粗心的用户)对您的文件具有写入权限可能会导致您的脚本执行awk可以执行的任何操作。