我正在从 BSD 转向完全的 Linux。 Ubuntu 16.04 中的脚本
#!/bin/sh
while (( "$#" )); do
case "$1" in
-i | --ignore-case)
[ $# -ne 2 ] && echo "2 arguments i needed" && exit 1
case_option=-i
;;
-*)
echo "Error: Unknown option: $1" >&2
exit 1
;;
*) # No more options
break
;;
esac
shift
done
# -o, if not, then ...
find $HOME ! -readable -prune -o \
-type f -name "*.tex" -exec grep -l $case_option "$1" {} + | vim -R -
错误在于循环。
sh ./script masi
返回与预期输出相同的输出。- 跑步
sh ./script -i masi
。输出:空白文件。预期输出:结果列表。 STOUT 是./script: 2: ./script: 2: not found Vim: Reading from stdin...
.
可能的错误
while (( "$#" ))
- ...
由于某种原因我根本无法使用这些选项。
转向 getopts - terdon 答案的动机
case_option=""
while getopts "i:" opt; do
case $opt in
i | ignore_case)
[[ $# -ne 2 ] && echo "2 arguments i needed" && exit 1
case_option=-i
;;
-*)
echo "Error: Unknown option: $1" >&2
exit 1
;;
*) # No more options
break
;;
esac
done
find $HOME ! -readable -prune -o \
-type f -name "*.tex" -exec grep -l $case_option "$1" {} + | vim -R -
在哪里
./script masi
通过或呼叫./script -i masi
。
如何while
循环处理案例?
答案1
dash
它失败是因为您使用and 而不是sh
or运行它bash
。在 Ubuntu 上,/bin/sh
是一个符号链接/bin/dash
,它是一个最小的、符合 POSIX 标准的 shell。最简单的解决方案是运行脚本,bash
而不是按预期工作:
bash ./script masi
另外,请注意您有一个 shebang 行:
#!/bin/sh
这意味着您不需要运行sh ./script
,您只需执行即可./script
。只需将 shebang 行更改为指向 bash 而不是sh
:
#/bin/bash
如果你坚持使用sh
(dash
在Ubuntu上),你需要将while
循环更改为:
while [ "$#" -gt 0 ]; do
或者,您可能想研究一下getopts
。
答案2
getopts
处理选项参数,你的脚本所做的将不起作用。
这是一个工作小框架:
case_option=""
while getopts "i:" opt; do
case $opt in
'i')
I_ARG=$OPTARG
;;
'?')
exit 1
;;
esac
done
shift $(($OPTIND - 1))
echo $@
答案3
以下是选项处理的两个示例,首先使用内置 shell getopts
,然后使用getopt
from util-linux
。
getopts
不支持--long
选项,仅支持短选项。
getopt
两者都支持。如果您想使用getopt
,请仅使用包中的版本util-linux
。不要使用 getopt 的任何其他版本,它们都已损坏且使用不安全,util-linux
是getopt
唯一有效的版本。
幸运的是,在 Linux 上,该util-linux
版本是您可能拥有的唯一版本,除非您特意安装了损坏的版本。
getopts
更便携(适用于大多数或所有 bourne-shell 后代),并且自动为您做更多事情(例如,需要较少的设置,您不需要运行shift
或shift 2
针对每个选项,具体取决于该选项是否带有参数)但能力较差(它不支持长选项)。
-i
无论如何,除了处理( ) 选项之外--ignore-case
,我还添加了-h
( --help
) 选项和需要参数-x
( --example
) 的选项示例。它没有任何用处,只是向您展示如何做到这一点。
对于getopts
,代码是:
#! /bin/bash
usage() {
# a function that prints an optional error message and some help.
# and then exits with exit code 1
[ -n "$*" ] && printf "%s\n" "$*" > /dev/stderr
cat <<__EOF__
Usage:
$0 [-h] [ -i ] [ -x example_data ]
-i Ignore case
-x The example option, requires an argument.
-h This help message.
Detailed help message here
__EOF__
exit 1
}
case_option=''
case_example=''
while getopts "hix:" opt; do
case "$opt" in
h) usage ;;
i) case_option='-i' ;;
x) case_example="$OPTARG" ;;
*) usage ;;
esac
done
shift $((OPTIND-1))
find "$HOME" ! -readable -prune -o -type f -name "*.tex" \
-exec grep -l ${case_option:+"$case_option"} "$1" {} + |
vim -R -
与getopt
来自util-linux
:
#! /bin/bash
usage() {
# a function that prints an optional error message and some help.
# and then exits with exit code 1
[ -n "$*" ] && printf "%s\n" "$*" > /dev/stderr
cat <<__EOF__
Usage:
$0 [ -h ] [ -i ] [ -x example_data ]
$0 [ --help ] [ --ignore-case ] [ --example example_data ]
-i, --ignore-case Ignore case
-x, --example The example option, requires an argument.
-h, --help This help message
Detailed help message here
__EOF__
exit 1
}
case_option=''
case_example=''
# getopt is only safe if GETOPT_COMPATIBLE is not set.
unset GETOPT_COMPATIBLE
# POSIXLY_CORRECT disables getopt parameter shuffling, so nuke it.
# parameter shuffling moves all non-option args to the end, after
# all the option args. e.g. args like "-x -y file1 file2 file3 -o optval"
# become "-x -y -o optval -- file1 file2 file3"
unset POSIXLY_CORRECT
OPTS_SHORT='hix:'
OPTS_LONG='help,ignore-case,example:'
# check options and shuffle them
TEMP=$(getopt -o "$OPTS_SHORT" --long "$OPTS_LONG" -n "$0" -- "$@")
if [ $? != 0 ] ; then usage ; fi
# assign the re-ordered options & args to this shell instance
eval set -- "$TEMP"
while true ; do
case "$1" in
-i|--ign*) case_option='-i' ; shift ;;
-x|--exa*) case_example="$2" ; shift 2 ;;
-h|--hel*) usage ;;
--) shift ; break ;;
*) usage ;;
esac
done
find "$HOME" ! -readable -prune -o -type f -name "*.tex" \
-exec grep -l ${case_option:+"$case_option"} "$1" {} + |
vim -R -