我正在制作一个小脚本。这只是我使用bash
脚本创建的第二个脚本。
基本上我想要这个脚本做的是获取用户输入并根据该选择触发命令。
正如您所看到的,用户首先输入他们要进入ssh的实例的主机地址,并最终登录。有几件事我不理解。
Line 2:
if [ "$mainmenuinput" = "1" ]; then
^-- SC2154: mainmenuinput is referenced but not assigned.
mainmenu() {
if [ "$mainmenuinput" = "1" ]; then
ssh "$customerurl" tail -f /data/jirastudio/jira/j2ee_*/log/main/current
elif [ "$mainmenuinput" = "2" ]; then
ssh "$customerurl" tail -f /data/jirastudio/confluence/j2ee_*/log/main/current
elif [ "$mainmenuinput" = "3" ]; then
ssh "$customerurl" tail -f /data/jirastudio/horde/service/log/main/current
elif [ "$mainmenuinput" = "4" ]; then
ssh "$customerurl" tail -f /data/jirastudio/apache/logs/access_log
fi
}
printf "\nEnter the customers host URL:\n"
read -r customerurl
printf "Press 1 for JIRA\n"
printf "Press 2 for Confluence\n"
printf "Press 3 for Horde\n"
printf "Press 4 for Apache Access\n"
printf "Press 5 for Apache Error\n"
read -p -r "Make your choice:" "$mainmenuinput"
查看SC2154条目我发现它意味着:
ShellCheck has noticed that you reference a variable that is not assigned. Double check that the variable is indeed assigned, and that the name is not misspelled.
我对这意味着什么有点困惑。如果有人可以解释,我会非常感激。
就目前而言,当我运行脚本时,它会暂停等待用户输入主机地址。用户点击ENTER
然后脚本会向他们显示菜单,让他们选择他们想要拖尾的日志。菜单看起来有点奇怪:
Press 1 for JIRA
Press 2 for Confluence
Press 3 for Horde
Press 4 for Apache Access
Press 5 for Apache Error
-r
我不确定为什么-r
出现在菜单的最后。选择完成后,脚本结束并输出:
./tail_logs.sh: line 23: read:
做出选择:':不是有效的标识符
任何有关这方面的帮助都会受到赞赏,或者如果有任何正确的方向推动。我喜欢搞清楚这些东西,但有时候,至少在错误/解决方案的大方向上推动它是有帮助的。
由于
编辑1
好的,我根据您的建议更新了我的脚本。它似乎仍然对一些事情犹豫不决。例如:
(mainmenu "$customerurl" "$mainmenuinput")
使用ShellCheck
我得到了回复:
Line 1:
(mainmenu "$customerurl" "$mainmenuinput") {
^-- SC2154: customerurl is referenced but not assigned.
^-- SC2154: mainmenuinput is referenced but not assigned.
^-- SC1070: Parsing stopped here. Mismatched keywords or invalid parentheses?
如果我这样写:
mainmenu() {
然后它没有抱怨。此外,如果我按照建议的方式运行脚本并输出它,我会收到关于“意外令牌附近的语法错误”的错误' {'
目前的代码如下:
#!/bin/sh
mainmenu() {
echo "$1"
echo "$2"
if [ "$2" = "1" ]; then
ssh "$1" tail -f "/data/jirastudio/jira/j2ee_*/log/main/current"
elif [ "$2" = "2" ]; then
ssh "$1" tail -f "/data/jirastudio/confluence/j2ee_*/log/main/current"
elif [ "$2" = "3" ]; then
ssh "$1" tail -f "/data/jirastudio/horde/service/log/main/current"
elif [ "$2" = "4" ]; then
ssh "$1" tail -f "/data/jirastudio/apache/logs/access_log"
elif [ "$2" > 4 || < 1 ]; then
echo "Uh uh uh, you didnt say the magic word! The number you picked isnt in the list. Pick again."
fi
}
echo
echo "Enter the customers host address:"
read -r customerurl
echo "Press 1 for JIRA"
echo "Press 2 for Confluence"
echo "Press 3 for Horde"
echo "Press 4 for Apache Access"
echo "Press 5 for Apache Error"
read -r -p "Pick a number: " mainmenuinput
运行时没有错误。但是当我做出选择时,脚本结束并且根本不输出tail命令。此外,我不确定我是否正确使用上一个elif
语句正确验证1-4以外的用户输入,但如果我将其更改为else
,则在运行脚本时出现错误。
我认为我的问题出在函数的第一部分?
mainmenu() {
echo "$1"
echo "$2"
如果没有$hostAddress
和mainMenuInput
,脚本就不知道应该将哪些内容分配给$1
和$2
,还是会自动将输入的第一个内容分配给这些变量?
答案 0 :(得分:3)
主要问题是最后使用read
命令。首先,紧跟在-p
选项之后的任何内容都用作提示字符串;在这种情况下,下一个参数是&#34; -r&#34;,因此它将其打印为提示。你显然想要&#34;做出你的选择:&#34;作为提示,因此必须在-p
之后立即进行(即使用read -r -p "Make your choice:" ...
或read -p "Make your choice:" -r ...
)。其次,当您使用$mainmenuinput
时,它会将其替换为mainmenuinput
的当前值。在shell中,您使用$variable
获取变量的值,而不是设置它。纠正这两个问题后,最后一个命令变为:
read -p "Make your choice:" -r mainmenuinput
另外一件重要的事情是:在阅读了用户之后&#39;输入,你需要实际调用mainmenu
函数。所以只需添加mainmenu
作为最后一行。
对于if ... then ... elif ...
结构,你的看起来很好;我不确定问题是什么。虽然我个人添加了一个else
子句,打印出该选项无效的错误。
我确实有一些风格/最佳实践建议:
最好以参数的形式将信息传递给函数,而不是全局变量。也就是说,不是直接在函数中使用customerurl
和mainmenuinput
,而是将它们作为参数传递(mainmenu "$customerurl" "$mainmenuinput"
),然后引用这些参数("$1"
和"$2"
)功能内部。这在像这样的小脚本中并不重要,但是在程序的不同部分使用的变量之间有明显的区别,这使得在更大的程序中更容易保持直接。
在shell脚本中,printf
是执行复杂操作的最佳方式,例如在最后没有换行的情况下打印行,或者翻译转义字符......但如果你只是在做标准的打印 - 换行 - 换行,echo
更简单。因此,我使用printf "something\n"
和echo "something"
替换各种printf "\nEnter the customers host URL:\n"
命令:
echo
echo "Enter the customers host URL:"
在命令
中ssh "$customerurl" tail -f /data/jirastudio/jira/j2ee_*/log/main/current
(或ssh "$1" ...
如果您遵循我关于参数而不是全局变量的建议,则通配符(*
)将在本地计算机上展开,然后交给ssh
并通过到要执行的远程计算机。最好引用这个论点来防止:
ssh "$customerurl" tail -f "/data/jirastudio/jira/j2ee_*/log/main/current"
请注意,引号在传递给ssh
然后传递到远程计算机之前将被删除,因此它们不会阻止在远程计算机上展开通配符。
您调用网址的内容实际上并不是网址;网址类似于&#34; https://stackoverflow.com/questions&#34;。他们从协议(或#34;计划&#34;)开始,如#34; http&#34;或&#34; ftp&#34;,然后&#34;://&#34;,然后是服务器名称,然后&#34; /&#34;等等。ssh
只需要原始服务器名称(可选择使用用户名,格式为user@server
)。
更新,基于编辑1:我不清楚如何调用该函数;你的定义(使用mainmenu() { ...
)是正确的,但是已经定义了你需要实际运行函数的函数。这样做,将脚本的结尾更改为:
...
echo "Press 5 for Apache Error"
read -r -p "Pick a number: " mainmenuinput
mainmenu "$customerurl" "$mainmenuinput"
这将运行该函数,第一个参数($1
)设置为"$customerurl"
,第二个参数($2
)设置为"$mainmenuinput"
。
您在函数中添加的elif
子句也存在问题。测试表达式的shell语法真的很奇怪(主要是出于历史原因)。此外,有三种常见的变体,原始的[ ... ]
(实际上是一个命令)具有最奇怪的语法,bash&#39; [[ ... ]]
变体(更清晰的语法,但在通用中不可用) POSIX shell)和(( ... ))
(更清晰的语法,数学 - 而不是面向字符串,不可移植)。有关详细信息,请参阅BashFAQ #31。
对于您尝试做的事情,其中任何一项都可行:
elif [ "$2" -gt 4 -o "$2" -lt 1 ]; then
# [ ... ] doesn't use || or &&, and uses -lt etc for numeric comparisons.
# < and > do string comparisons, which are ... different. And you'd
# need to quote them to keep them from being mistaken for redirects.
# Also, you need to specify the "$2" explicitly for each comparison.
elif [[ "$2" -gt 4 || "$2" -lt 1 ]]; then
# [[ ... ]] uses || and &&, but still uses -lt etc for numeric comparisons.
# < and > still do string comparisons, but don't need to be quoted
elif (( $2 > 4 || $2 < 1 )); then
# All numeric here, so < and > work
但是仍然存在一个问题,因为用户可能输入了根本没有数字的东西(只需按下返回,键入&#34; wibble&#34;等),然后所有这些情况下数字比较都会失败。解决方案:跳过测试,并使用else
代替elif
:
...
elif [ "$2" = "4" ]; then
ssh "$1" tail -f "/data/jirastudio/apache/logs/access_log"
else
echo "Uh uh uh, you didnt say the magic word! The number you picked isnt in the list. Pick again."
fi
}
......就这样,如果以前的任何条件因而无法满足,则会打印错误信息。