从 TSV 文件执行命令和参数

Execute commands and arguments from TSV file

我有一个 TSV 文件,其中每一行代表一个命令和命令行参数。像这样:

ls      ~
cd      /home
cp      dir1    dir2

每行的列数可能不定。每个单元格可以包含空格、单引号和双引号。

执行此操作的好方法是什么?

使用 Bash,将 IFS 设置为选项卡读入数组:

$ cat data
ls      ~
cd      /home
cp      dir1    dir2
al      a b       c  d  
$ vis -t -n data
ls^I~^J
cd^I/home^J
cp^Idir1^Idir2^J
al^Ia b^I  c  d  ^J
$ while IFS=$'\t' read -r -a xyz; do al "${xyz[@]}"; done < data
ls
~
cd
/home
cp
dir1
dir2
al
a b
  c  d  
$ while IFS=$'\t' read -r -a xyz; do al "${xyz[@]}"; done < data | vis -t -n
ls^J
~^J
cd^J
/home^J
cp^J
dir1^J
dir2^J
al^J
a b^J
  c  d  ^J
$

带有选项 -t -nvis 程序将制表符打印为 ^I 并将换行符打印为 ^J(后跟换行符); al 程序每行打印一个参数——它实际上等同于 printf "%s\n" "$@"(它实际上是一个非常简单的 C 程序,但结果是相同的)。

在要执行的文件中使用真正的命令,你会写:

while IFS=$'\t' read -r -a xyz; do "${xyz[@]}"; done < data

在我的机器上,我得到:

$ (while IFS=$'\t' read -r -a xyz; do "${xyz[@]}"; done < data )
ls: ~: No such file or directory
cp: dir1: No such file or directory
a b
  c  d  
$

我使用了子目录shell,因为我不想将当前目录留在主目录shell,而且我没有要复制的dir1dir2。请注意,shell 没有对参数扩展的结果进行波浪号扩展,因此 ls 看到了一个实际的波浪号,而不是我的主目录的值。修复波浪号扩展会很痛苦——非常痛苦(请参阅 Tilde expansion in quotes). It also means range notation such as {1..10} would not be expanded, and that aliases would not be expanded. See Shell expansions 了解会发生什么和不会发生什么。

解法:

ruby -ne 'require "shellwords"; system $_.chomp.split("\t").shelljoin'

证明:

这是我们的测试脚本:cat printArguments.bash:

#!/bin/bash
args=("$@")
for ((i=0; i < $#; i++)) {
   echo "argument $((i+1)): ${args[$i]}"
}

和测试用例:

echo $'./printArguments.bash\t1\t\t3' | ruby -ne 'require "shellwords"; system $_.chomp.split("\t").shelljoin'

结果:

argument 1: 1

argument 2:

argument 3: 3