我有一个实用程序(myutil
),我需要传递多个参数。参数可能(将)包含反斜杠和空格,因此需要用单引号括起来。此实用程序的示例运行是:
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
我正在编写一个脚本,它将从多行文件中读取这些参数并将它们提供给脚本。输入文件myinput.txt如下所示:
# cat myinput.txt
ONE\APPLE
ONE\PEAR
TWO\RED GRAPE
TWO\TOMATO
我使用以下代码来解析文件并执行myutil
。该脚本将每一行作为参数读取,并用双引号将其括起来(因为myutil
期望具有空格或特殊字符的值)并创建一个单独的变量来保存整个参数字符串:
#!/bin/sh
MYCOMMAND=myutil
if [ -f myinput.txt ]; then
ARGSLIST=`cat myinput.txt| sed -e 's/^/"/g' -e 's/$/"/g' | awk '{ printf "%s ", $0 }'`
$MYCOMMAND setOptions "${ARGSLIST}"
printf "%s\n" "$MYCOMMAND setOptions ${ARGSLIST}"
fi
正如我所料,此命令的屏幕输出看起来像预期的那样:
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
但是,实际上并不是基于myutil
通常如何处理此命令而执行的操作。相反,myutil
正在处理此问题,好像所有参数都包含在单引号中。在sh
下运行此调试并不反映这一点:
+ MYCOMMAND=myutil
+ [ -f myinput.txt ]
+ awk { printf "%s ", $0 }
+ sed -e s/^/"/g -e s/$/"/g
+ cat myinput.txt
+ ARGSLIST="ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
+ myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
+ printf %s\n myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
但是,在bash
下运行调试似乎显示了实际执行的内容:
+ MYCOMMAND=myutil
+ '[' -f myinput.txt ']'
++ awk '{ printf "%s ", $0 }'
++ sed -e 's/^/"/g' -e 's/$/"/g'
++ cat myinput.txt
+ ARGSLIST='"ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
+ myutil setOptions '"ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
+ printf '%s\n' 'myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
您可以看到调试行显示为:
+ myutil setOptions '"ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
该行实际上是基于我在我的util中看到的输出执行的内容,但是打印到屏幕上的内容是前面提到的减去单引号:
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
我需要在屏幕上显示的是实际执行的内容,而不是带有单引号的版本,因为它为myutil
提供了一个毫无价值的巨型参数。
我有两种解决方案,我都不确定这是解决此问题的最佳方法。
第一个是简单地使用eval:
#!/bin/sh
MYCOMMAND=myutil
if [ -f myinput.txt ]; then
ARGSLIST=`cat myinput.txt| sed -e 's/^/"/g' -e 's/$/"/g' | awk '{ printf "%s ", $0 }'`
eval $MYCOMMAND setOptions "${ARGSLIST}"
printf "%s\n" "$MYCOMMAND setOptions ${ARGSLIST}"
fi
第二个是使用xargs:
#!/bin/sh
MYCOMMAND=myutil
if [ -f myinput.txt ]; then
ARGSLIST=`cat myinput.txt| sed -e 's/^/"/g' -e 's/$/"/g' | awk '{ printf "%s ", $0 }'`
printf "%s\n" "$ARGSLIST" | xargs $MYCOMMAND setOptions
printf "%s\n" "$MYCOMMAND setOptions ${ARGSLIST}"
fi
我很难相信xargs
是必需的,而且我一直在阅读如何使用eval
可能也不是推荐的选择。
我已经看到了一些类似的主题,建议使用数组,但我无法正确地将他们的建议应用于我的示例。另外,我需要这个解决方案在bourne sh
下运行,并且尽可能便携,因为它将在大多数标准版本的Linux / UNIX上运行。我不相信sh
支持其他解决方案推荐的类型的数组。
执行命令的最佳方法是什么,因为它实际显示在屏幕上而没有shell提供额外的引用?
答案 0 :(得分:0)
您可以定义一个递归shell函数,该函数一次从其标准输入中读取一行以构建命令行。当没有更多输入可用时,实际命令将使用累积的参数运行。递归会增加一些开销,但我假设输入文件不是很大。
anuar