从 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 -n
的 vis
程序将制表符打印为 ^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,而且我没有要复制的dir1
至 dir2
。请注意,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
我有一个 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 -n
的 vis
程序将制表符打印为 ^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,而且我没有要复制的dir1
至 dir2
。请注意,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