我是否正确设置此脚本以根据用户输入运行特定命令?

时间:2016-08-09 23:38:10

标签: linux bash shell

我正在制作一个小脚本。这只是我使用bash脚本创建的第二个脚本。

基本上我想要这个脚本做的是获取用户输入并根据该选择触发命令。

正如您所看到的,用户首先输入他们要进入ssh的实例的主机地址,并最终登录。有几件事我不理解。

  1. If / Then / Else / Elif - 这个概念看起来很简单,但也许这些应该如何用到我身上。
  2. 当我通过bash解析器运行我的脚本时,解析器返回以下消息:
  3. 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"
    

    如果没有$hostAddressmainMenuInput,脚本就不知道应该将哪些内容分配给$1$2,还是会自动将输入的第一个内容分配给这些变量?

1 个答案:

答案 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子句,打印出该选项无效的错误。

我确实有一些风格/最佳实践建议:

  • 最好以参数的形式将信息传递给函数,而不是全局变量。也就是说,不是直接在函数中使用customerurlmainmenuinput,而是将它们作为参数传递(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然后传递到远程计算机之前将被删除,因此它们不会阻止在远程计算机上展开通配符。

    < / LI>
  • 您调用网址的内容实际上并不是网址;网址类似于&#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
}

......就这样,如果以前的任何条件因而无法满足,则会打印错误信息。