2

我正在学习 shell 脚本,并且发现很难找到一个好的学习方法。我在下面创建了一个脚本,让用户可以通过选项搜索各种不同的 Internet 引擎。如果有人能仔细阅读并指出我做错了什么,如何改进它等,我将不胜感激。

#!/bin/bash

## Get user search-engine option
while getopts aegwy: OPTIONS ; do
  case "$OPTIONS" in 
    a) ENGINE="http://www.amazon.com/s/ref=nb_sb_noss/?field-keywords";;
    e) ENGINE="http://www.ebay.com/sch/i.html?_nkw";;
    g) ENGINE="http://www.google.com/search?q";;
    w) ENGINE="http://en.wikipedia.org/wiki/?search";;
    y) ENGINE="http://www.youtube.com/results?search_query";;
    ?) ERRORS=true;;
  esac
done &>/dev/null

## Ensure correct command usage
[ $# -ne 2 ] || [ $ERRORS ] && printf "USAGE: $(basename $0) [-a Amazon] [-e eBay] [-g Google] [-w Wikipedia] [-y YouTube] \"search query\"\n" && exit 1

## Ensure user is connected to the Internet
ping -c 1 209.85.147.103 &>/dev/null ; [ $? -eq 2 ] && printf "You are not connected to the Internet!\n" && exit 1

## Reformat the search query
QUERY=`printf "$2" | sed 's/ /+/g'`

## Execute the search and exit program
which open &>/dev/null ; [ $? -eq 0 ] && open "$ENGINE"="$QUERY" &>/dev/null && exit 0 || xdg-open "$ENGINE"="$QUERY" &>/dev/null && exit 0 || printf "Command failed!\n" && exit 1

在此先感谢大家,意义重大!

4

2 回答 2

2

最好在 codereviews 中发布,如上所述,但这里有一些主要是文体评论。我应该强调的是,该脚本原样非常好;这些只是我认为将有助于使代码更易于阅读/维护,在某些情况下更健壮等的小改进。

您不需要仅仅因为环境变量是全大写,就对变量名使用全大写;shell变量和环境变量不是一回事。

由于您的$OPTIONS变量一次只包含一个选项,因此单数名称会更好(例如$option)。或者你可以选择$opt,这在这里有点传统。

您的:getopts 字符串 ( aegwy:) 中的 表明该-y选项需要一个参数,就像在-y某些东西中一样,而不仅仅是-y其本身。由于您没有对 做任何事情$OPTARG,我猜这不是故意的。

正如其他人所说, an if/ then/ elif/else可能比 and 的链更&&清晰||

测试[ $ERRORS ]有点不清楚,因为它可能意味着很多不同的东西,具体取决于$ERRORS参数的内容。一个更明确的指示,表明您只关心它是否设置为[ -n "$ERRORS" ].

喜欢[ -ne ]和朋友的比较大多是在 shell 内置整数运算之前的遗留物;更现代的成语将是(( $# != 2 ))

您的使用消息暗示 -a、-e、-g、-w 和 -y 选项采用 Amazon、eBay、Google 等形式的参数。如果没有这些添加,命令的实际语法会更清楚; 您可以在帮助文本中包含一个额外的段落,列出每个选项的含义。

通常,错误消息应该发送到 stderr 而不是 stdout ( >&2)。

basename $0使用它来保持输出的一致性很好,但有一些事情要说不要管$0,因为它会反映用户实际调用命令的方式。需要考虑的事情。

printf如果您不使用格式字符串,则使用意义不大;只需使用echo,它会自动附加换行符。使用消息传统上也不包含引号。是否需要引用 arg 取决于用户。

检查命令是否成功正是工作原理,因此除非您真的关心确切的退出值,否则if无需进行显式检查。$?在连接 ping 的情况下,您可能不关心它失败的原因,只关心它确实:

  if ! ping -c 1 209.85.147.103 >/dev/null; then 
     echo >&2 "$0: You are not connected to the Internet!"
     exit 1
  fi

您的搜索查询重新格式化可能需要做的不仅仅是将空格变成加号;如果它有一个&符号怎么办?但是,如果您只是在做空格到加号的事情,您可以使用 bash 参数扩展来完成,而无需 sed:QUERY="${QUERY// /+}"

如果你的程序依赖于 open/xdg-open 等,你应该在顶部检查它的可用性;如果您知道无论如何都无法执行请求的操作,那么做任何其他事情都没有意义。你可以使用一个变量,这样你就不会在多个子句中重复自己:

open=
for cmd in open xdg-open; do
   if type -p "$cmd" >/dev/null; then
     open="$cmd"
     break
   fi
done
if [ -z "$open" ]; then
   echo >&2 "$0: open command not found."
   exit 1
fi

然后你就可以完成这一行:

"$open" "$ENGINE=$QUERY" &>/dev/null

于 2012-04-13T20:43:12.350 回答
0

http://linuxcommand.org/是提高 bash 脚本技能的绝佳资源。

http://tldp.org/LDP/abs/html/是另一个很棒的文档。

希望这可以帮助。

于 2012-04-12T07:06:51.837 回答