简体   繁体   English

Bash脚本中的RegEx(for-loop)

[英]RegEx in bash-script (for-loop)

I want to parse the arguments given to a shell script by using a for-loop. 我想通过使用for循环解析给shell脚本的参数。 Now, assuming I have 3 arguments, something like for i in $1 $2 $3 should do the job, but I cannot predict the number of arguments, so I wanted use an RegEx for the range and $# as the number of the last argument. 现在,假设我有3个参数,像for i in $1 $2 $3这样的东西应该可以完成这项工作,但我无法预测参数的数量,所以我想使用RegEx作为范围,$#作为最后一个参数的数量。 I don't know how to use these RegEx' in a for-loop, I tried something like for i in $[1-$#] which doesn't work. 我不知道如何在for循环中使用这些RegEx',我for i in $[1-$#]尝试了类似于for i in $[1-$#]东西for i in $[1-$#]但这不起作用。 The loop only runs 1 time and 1-$# is being calculated, not used as a RegEx. 该循环仅运行1次,并且计算1 - $#,而不是用作RegEx。

Basic 基本

A for loop by default will loop over the command-line arguments if you don't specify the in clause: 如果未指定in子句,则默认情况下, for循环将循环执行命令行参数:

for arg; do
    echo "$arg"
done

If you want to be explicit you can get all of the arguments as "$@" . 如果你想要明确,你可以把所有的参数都称为"$@" The above loop is equivalent to: 上面的循环相当于:

for arg in "$@"; do
    echo "$arg"
done

From the bash man page: 从bash手册页:

Special Parameters 特殊参数

$@ — Expands to the positional parameters, starting from one. $@ - 从一个开始扩展到位置参数。 When the expansion occurs within double quotes, each parameter expands to a separate word. 当扩展发生在双引号内时,每个参数都会扩展为单独的单词。 That is, "$@" is equivalent to "$1" "$2" ... . 也就是说, "$@"相当于"$1" "$2" ... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. 如果双引号扩展发生在一个单词中,则第一个参数的扩展与原始单词的开头部分连接,最后一个参数的扩展与原始单词的最后一部分连接。 When there are no positional parameters, "$@" and $@ expand to nothing (ie, they are removed). 当没有位置参数时, "$@"$@扩展为空(即,它们被删除)。

Advanced 高级

For heavy-duty argument processing, getopt + shift is the way to go. 对于重载参数处理, getopt + shift是要走的路。 getopt will pre-process the command-line to give the user some flexibility in how arguments are specified. getopt将预处理命令行,为用户提供一些指定参数的灵活性。 For example, it will expand -xzf into -x -z -f . 例如,它会将-xzf扩展为-x -z -f It adds a -- argument after all the flags which separates flags from file names; 它在将标志与文件名分开的所有标志之后添加一个--参数; this lets you do run cat -- -my-file to display the contents of -my-file without barfing on the leading dash. 这让你运行cat -- -my-file显示的内容-my-file ,而不barfing在领先冲刺。

Try this boilerplate code on for size: 试试这个样板代码的大小:

#!/bin/bash

eval set -- "$(getopt -o a:bch -l alpha:,bravo,charlie,help -n "$0" -- "$@")"

while [[ $1 != -- ]]; do
    case "$1" in
      -a|--alpha)
        echo "--alpha $2"
        shift 2
        ;;

      -b|--bravo)
        echo "--bravo"
        shift
        ;;

      -c|--charlie)
        echo "--charlie"
        shift
        ;;

      -h|--help)
        echo "Usage: $0 [-a ARG] [-b] [-c]" >&2
        exit 1
        ;;
    esac
done
shift

Notice that each option has a short a long equivalent, eg -a and --alpha . 请注意,每个选项都有一个短的等长,例如-a--alpha The -a flag takes an argument so it's specified as a: and alpha: in the getopt call, and has a shift 2 at the end of its case. -a标志接受一个参数,因此在getopt调用中将其指定为a:alpha: getopt并在其大小写结尾处有一个shift 2

Another way to iterate over the arguments which is closer to what you were working toward would be something like: 迭代更接近你正在努力的论点的另一种方法是:

for ((i=1; i<=$#; i++))
do
    echo "${@:i:1}"
done

but the for arg syntax that John Kugelman showed is by far preferable. 但是John Kugelman所展示的for arg语法是最好的。 There are, however, times when array slicing is useful. 但是,有时阵列切片很有用。 Also, in this version, as in John's, the argument array is left intact. 此外,在此版本中,与John的一样,参数数组保持不变。 Using shift discards its elements. 使用shift会丢弃其元素。

You should note that what you were trying to do with square brackets is not a regular expression at all. 您应该注意,您尝试使用方括号的内容根本不是正则表达式。

I suggest doing something else instead: 我建议做其他事情:

while [ -n "$1" ] ; do
  # Do something with $1
  shift
  # Now whatever was in $2 is now in $1
done

The shift keyword moves the content of $2 into $1, $3 into $2, etc. pp. shift关键字将$ 2的内容转换为$ 1,将$ 3的内容转换为$ 2等.pp。

Let's say the arguments where: 让我们说下面的论点:

a b c d

After a shift , the arguments are now: shift ,争论现在是:

b c d

With the while loop, you can thus parse an arbitrary number of arguments and can even do things like: 使用while循环,您可以解析任意数量的参数,甚至可以执行以下操作:

while [ -n "$1" ] ; do
  if [ "$1" = "-f" ] ; then
    shift
    if [ -n "$1" ] ; then
      myfile="$1"
    else
      echo "-f needs an additional argument"
    end
  fi
  shift
done

Imagine the arguments as being an array and $n being indexes into that array. 想象一下,参数是一个数组,$ n是该数组的索引。 shift removes the first element, so the index 1 now references the element that was at index 2 prior to shift . shift删除第一个元素,因此索引1现在引用shift之前索引为2的元素。 I hope you understand what I want to say. 我希望你明白我想说的话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM