我有一个TSV文件,其中每一行代表一个命令和命令行参数。像这样:
ls ~
cd /home
cp dir1 dir2
每行可能有不同数量的列。每个单元格可能包含空格,单引号和双引号。
执行此操作的好方法是什么?
答案 0 :(得分:1)
使用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
$
带有选项vis
的{{1}}程序将标签打印为-t -n
,将换行打印为^I
(后跟换行符); ^J
程序每行打印一个参数 - 它实际上等同于al
(它实际上是一个非常简单的C程序,但结果是一样的。)
使用要执行的文件中的实际命令,您可以写:
printf "%s\n" "$@"
在我的机器上,我得到了:
while IFS=$'\t' read -r -a xyz; do "${xyz[@]}"; done < data
我使用了子shell,因为我不想将当前目录保留在主shell中,而且我没有$ (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
$
被复制到dir1
。请注意,shell没有对参数扩展的结果进行波浪扩展,因此dir2
必须看到实际的波形符号,而不是我的主目录的值。固定波浪形扩展将是痛苦的 - 极度痛苦(见Tilde expansion in quotes)。它还意味着范围表示法如ls
不会被扩展,并且不会扩展别名。请参阅Shell expansions了解会发生什么,不会发生什么。
答案 1 :(得分:0)
<强>解决方案:强>
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'
结果:
参数1:1
参数2:
论证3:3