这个问题有三个部分,每个部分都很简单,但结合在一起并不是微不足道的(至少对我而言):))
需要编写一个应该作为其参数的脚本:
示例:
./my_script head -100 a.txt b.txt ./xxx/*.txt
./my_script sed -n 's/xxx/aaa/' *.txt
等等。
出于某种原因我的脚本内部需要区分
所以编写上述示例的最标准方法可能是:
./my_script head -100 -- a.txt b.txt ./xxx/*.txt
./my_script sed -n 's/xxx/aaa/' -- *.txt
问题1:这里有更好的解决方案吗?
./my_script中的处理(第一次尝试):
command="$1";shift
args=`echo $* | sed 's/--.*//'`
filenames=`echo $* | sed 's/.*--//'`
#... some additional processing ...
"$command" "$args" $filenames #execute the command with args and files
当filenames
包含spaces
和/或' - '时,此解决方案将失败,例如
/ some - path / to / more / idiotic file name.txt
问题2:如何正确获取$command
$args
和$filenames
以供日后执行?
问题3: - 如何实现以下执行方式?
echo $filenames | $command $args #but want one filename = one line (like ls -1)
这里是不错的shell解决方案,还是需要使用例如perl?
答案 0 :(得分:6)
首先,听起来你正在尝试编写一个带有命令和文件名列表的脚本,并依次对每个文件名运行命令。这可以在bash的一行中完成:
$ for file in a.txt b.txt ./xxx/*.txt;do head -100 "$file";done $ for file in *.txt; do sed -n 's/xxx/aaa/' "$file";done
然而,也许我误解了你的意图所以让我单独回答你的问题。
而不是使用“ - ”(已经有不同的含义),以下语法对我来说更自然:
./my_script -c "head -100" a.txt b.txt ./xxx/*.txt ./my_script -c "sed -n 's/xxx/aaa/'" *.txt
要在bash中提取参数,请使用getopts
:
SCRIPT=$0
while getopts "c:" opt; do
case $opt in
c)
command=$OPTARG
;;
esac
done
shift $((OPTIND-1))
if [ -z "$command" ] || [ -z "$*" ]; then
echo "Usage: $SCRIPT -c <command> file [file..]"
exit
fi
如果要为每个剩余的参数运行命令,它将如下所示:
for target in "$@";do
eval $command \"$target\"
done
如果你想从STDIN读取文件名,它看起来会更像这样:
while read target; do
eval $command \"$target\"
done
答案 1 :(得分:3)
引用$@
变量时,可以将参数分组:
for parameter in "$@"
do
echo "The parameter is '$parameter'"
done
如果给出:
head -100 test this "File name" out
将打印
the parameter is 'head'
the parameter is '-100'
the parameter is 'test'
the parameter is 'this'
the parameter is 'File name'
the parameter is 'out'
现在,您所要做的就是解析循环。您可以使用一些非常简单的规则:
您可以使用以下方法检查参数中的第一个字符是否为破折号:
if [[ "x${parameter}" == "x${parameter#-}" ]]
如果您之前没有看过这种语法,那就是左侧过滤器。 #
将变量名的两部分分开。第一部分是变量的名称,第二部分是要切断的 glob 过滤器(不是正则表达式)。在这种情况下,它是一个短划线。只要这个陈述不正确,你知道你有一个参数。顺便说一下,在这种情况下可能需要或不需要x
。当你运行一个测试,并且你有一个带有破折号的字符串时,测试可能会将它误认为测试参数而不是值。
把它放在一起会是这样的:
parameterFlag=""
for parameter in "$@" #Quotes are important!
do
if [[ "x${parameter}" == "x${parameter#-}" ]]
then
parameterFlag="Tripped!"
fi
if [[ "x${parameter}" == "x--" ]]
then
print "Parameter \"$parameter\" ends the parameter list"
parameterFlag="TRIPPED!"
fi
if [ -n $parameterFlag ]
then
print "\"$parameter\" is a file"
else
echo "The parameter \"$parameter\" is a parameter"
fi
done
答案 2 :(得分:0)
问题1
我不这么认为,至少不是你需要为任意命令做这件事。
问题3
command=$1
shift
while [ $1 != '--' ]; do
args="$args $1"
shift
done
shift
while [ -n "$1" ]; do
echo "$1"
shift
done | $command $args
问题2
与问题3有何不同?