首先发布在这里!我真的需要这方面的帮助,我在谷歌看了问题,但无法找到一个有用的答案给我。所以这就是问题所在。 我很乐意用bash中的框架编写一些代码。每个人都可以创建自己的模块并将其添加到框架中。但。要知道脚本需要什么参数,我创建了一个必须在每个模块中的“args.conf”文件,它看起来像这样:
LHOST;true;The IP the remote payload will connect to.
LPORT;true;The port the remote payload will connect to.
第一列是参数名称,第二列定义是否需要,第三列是描述。无论如何,长话短说,框架应该逐行读取args.conf文件,以询问用户每个参数的值。这是一段代码:
info "Reading module $name argument list..."
while read line; do
echo $line > line.tmp
arg=`cut -d ";" -f 1 line.tmp`
requ=`cut -d ";" -f 2 line.tmp`
if [ $requ = "true" ]; then
echo "[This argument is required]"
else
echo "[This argument isn't required, leave a blank space if you don't wan't to use it]"
fi
read -p " $arg=" answer
echo $answer >> arglist.tmp
done < modules/$name/args.conf
tr '\n' ' ' < arglist.tmp > argline.tmp
argline=`cat argline.tmp`
info "Launching module $name..."
cd modules/$name
$interpreter $file $argline
cd ../..
rm arglist.tmp
rm argline.tmp
rm line.tmp
succes "Module $name execution completed."
正如您所看到的,它应该向用户询问每个参数的值......但是:
1)读命令似乎没有执行。它只是跳过它,而且参数没有值
2)尽管args.conf文件包含3行,但循环似乎只执行一次。我在屏幕上看到的只是“[这个参数是必需的]”只是一次,并且模块刚刚启动(并且崩溃,因为它没有所需的参数......)。
真的不知道该怎么办,这里......我希望有人在这里有一个答案^^'。 提前谢谢!
(抱歉最终错误,我是法国人)
α
答案 0 :(得分:2)
正如其他人在评论中指出的那样,问题是循环中的所有read
命令都是从args.conf文件读取的,而不是用户。我处理这个问题的方法是将conf文件重定向到与stdin不同的文件描述符(fd#0);我喜欢使用fd#3:
while read -u3 line; do
...
done 3< modules/$name/args.conf
(注意:如果您的shell read
命令无法理解-u
选项,请改用read line <&3
。)
此脚本中还有许多其他内容我建议不要:
不带双引号的变量引用,例如echo $line
代替echo "$line"
,< modules/$name/args.conf
代替< "modules/$name/args.conf"
。不带引号的变量引用会被拆分为单词(如果它们包含空格),并且恰好匹配文件名的任何通配符都将被匹配文件列表替换。这可能导致真正奇怪和间歇性的错误。不幸的是,您对$argline
的使用取决于单词拆分以分隔多个参数;如果你正在使用bash
(不是通用的POSIX shell),你可以使用数组;我会做到的。
您在任何地方使用相对文件路径,并在脚本中cd
。这往往是脆弱和混乱,因为文件路径在脚本中的不同位置是不同的,并且用户传入的任何相对路径将在脚本cd
第一次在其他地方时变为无效。更糟糕的是,当你cd
时,你没有检查错误,所以如果任何cd
因任何原因失败,那么整个脚本的其余部分将在错误的地方运行并且奇怪地失败。最好不要弄清楚系统根目录的位置(作为绝对路径),然后引用它的所有内容(例如< "$module_root/modules/$name/args.conf"
)。
实际上,您并未在任何地方检查错误。在编写任何类型的程序时,通常都是一个好主意,试图想出可能出现的问题以及程序应该如何响应(并且还期望你没有想到的事情也会发生错误)。有些人喜欢使用set -e
在任何简单命令失败时退出脚本,但是this doesn't always do what you'd expect。我更喜欢在我的脚本中显式测试命令的退出状态,例如:
command1 || {
echo 'command1 failed!' >&2
exit 1
}
if command2; then
echo 'command2 succeeded!' >&2
else
echo 'command2 failed!' >&2
exit 1
fi
您正在当前目录中创建临时文件,这会冒随机冲突(与其他同时运行的脚本,任何碰巧有您正在使用的名称的文件等) )。最好在开头创建一个临时目录,然后将所有内容存储在其中(再次,通过绝对路径):
module_tmp="$(mktemp -dt module-system)" || {
echo "Error creating temp directory" >&2
exit 1
}
...
echo "$answer" >> "$module_tmp/arglist.tmp"
(顺便说一句,请注意我使用$()
代替反叛。他们更容易阅读,并且没有反引号有一些微妙的句法怪异。我建议切换。)
说到这,你过度使用临时文件;使用shell变量和内置shell功能可以很好地完成很多你正在做的事情。例如,不是从配置文件中读取行,而是将它们存储在临时文件中并使用cut
将它们拆分为字段,您只需echo
到cut
:
arg="$(echo "$line" | cut -d ";" -f 1)"
...或者更好的是,使用read
的内置功能根据IFS
设置的内容来分割字段:
while IFS=";" read -u3 arg requ description; do
(注意,由于IFS
的赋值是read
命令的前缀,它只影响那一个命令;全局更改IFS
会产生奇怪的效果,应该避免只要有可能。)
类似地,将参数列表存储在文件中,将换行符转换为空格,然后读取该文件......您可以跳过任何或所有这些步骤。如果您正在使用bash
,请将arg列表存储在数组中:
arglist=()
while ...
arglist+=("$answer") # or ("#arg=$answer")? Not sure of your syntax.
done ...
"$module_root/modules/$name/$interpreter" "$file" "${arglist[@]}"
(这种混乱的语法,带有双引号,花括号,方括号和at符号,是在bash
中展开数组的一般正确方法。
如果你不能指望数组之类的bash
扩展,你至少可以用一个简单的变量来解决这个问题:
arglist=""
while ...
arglist="$arglist $answer" # or "$arglist $arg=$answer"? Not sure of your syntax.
done ...
"$module_root/modules/$name/$interpreter" "$file" $arglist
...但是这会冒成分词和/或扩展到文件列表的风险。