为什么这个 while-case 在 Ubuntu 中不起作用?

为什么这个 while-case 在 Ubuntu 中不起作用?

我正在从 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 而不是shor运行它bash。在 Ubuntu 上,/bin/sh是一个符号链接/bin/dash,它是一个最小的、符合 POSIX 标准的 shell。最简单的解决方案是运行脚本,bash而不是按预期工作:

bash ./script masi

另外,请注意您有一个 shebang 行:

#!/bin/sh

这意味着您不需要运行sh ./script,您只需执行即可./script。只需将 shebang 行更改为指向 bash 而不是sh

#/bin/bash

如果你坚持使用shdash在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,然后使用getoptfrom util-linux

getopts不支持--long选项,仅支持短选项。

getopt两者都支持。如果您想使用getopt,请仅使用包中的版本util-linux不要使用 getopt 的任何其他版本,它们都已损坏且使用不安全,util-linuxgetopt唯一有效的版本。

幸运的是,在 Linux 上,该util-linux版本是您可能拥有的唯一版本,除非您特意安装了损坏的版本。

getopts更便携(适用于大多数或所有 bourne-shell 后代),并且自动为您做更多事情(例如,需要较少的设置,您不需要运行shiftshift 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 -

相关内容