【问题标题】:Bash Arrays - Dynamically AddingBash 数组 - 动态添加
【发布时间】:2013-02-18 22:39:30
【问题描述】:

谁能帮我写一个简单的 bash 脚本来处理以下用法:

./application channels;message

eg:  ./application channel1 channel2 channel3;this is a message

所以基本上是分隔符之前的任何内容;是由空格分隔的通道,以及 ; 之后的任何内容是消息。

基本上,我想将这些中的每一个存储到一个变量中并打印出来......

【问题讨论】:

  • 请注意,; 是 shell 的命令分隔符。您必须写:./application 'channels;message',分号前后加上引号或反斜杠。那不是很正统的用法。你可以更习惯地使用./application -m "this is a message" channel1 channel2 channel3
  • 嗨乔纳森 - 感谢您的反馈。我怎么能用你的用处写一个脚本呢?我看到的唯一问题是,如果消息中有 " 字符怎么办。code./application -m "this is"t a message" channel1 etc...
  • 您需要了解 shell 元字符,其中包括 "'`$;(。对于所有这些,您需要转义罪魁祸首:./application -m 'He said, "Don'\''t do that!"' chan1 等。通常,在消息周围使用单引号;如果要写单引号,请输入 '\''

标签: bash arguments


【解决方案1】:

由于您需要一条消息和一个或多个通道,因此首先指定消息更有意义,然后假设其余参数是通道。类似的东西

#!/bin/bash

message="$1"
shift  # Now each argument in $@ is a channel

那么你的脚本可以如下运行

$ ./application "This is a message" channel1 channel2 channel3

虽然这是您通常处理所需参数的方式,但与使用 -m 指定消息相比的一个缺点是更难判断用户是否忘记指定消息

# Is "channel1" the message, or did the user forget to specify one?
$ ./application channel1 channel2 channel3

关于实现-m,我推荐你Jonathan Leffler's answer

【讨论】:

  • 如果消息是强制性的,避免要求选项字母是有意义的;这是现代风格。可以将消息作为最后一个参数,但这更难处理。至少bash$20 识别为第20 个参数,而(非常!)旧的Bourne shell 仅识别$1..$9,因此$20 被视为$2 与零连接。 OTOH,您仍然必须使用${!#} 解决最后一个参数(查找Shell Parameter Expansion)。
  • 位置参数 > 9 需要大括号"${10}"$20 仍然是 "${2}0"。传家宝仍然无法处理>$9。大多数支持下标扩展的 Korn 衍生物(bash、zsh 等)都可以使用 "${@: -1}"(pdksh/mksh 仍然无法将特殊扩展映射到多字扩展。显然这在待办事项列表中。)${!#} 仅适用于重击。具有“惰性”名称引用(bash 4.3、mksh)的 shell 可以将 typeset -n last=$#; echo "$last" 作为等效项。
【解决方案2】:

您可能想寻找另一种方式来分隔消息,因为分号会导致 bash 读取到分号并“认为这是命令的结尾”。然后 bash 将使用分号之前的参数运行您的程序。随后,它将寻找一个名为“this”的程序或内置程序,并提供“is”、“a”和“message”作为 this 的命令行参数。但是 bash 可能会回答“this: command not found”。 有关更多信息,请查看 bash manual 中的 ';'/分号运算符的含义。

你可能会做如下的事情

#!/bin/bash

message=""
outfiles=""

# Loop until all parameters are used up
# shift "eats" one argument at a time
# util there are no arguments left then $1 is a emtpy string
while [ "$1" != "" ]; do

    if [ "$1" == "-m" ] # the message
    then
        shift #"eat one arugment then $1 is your message"
        #you should check if there is a argument after "-m"
        message=$1
    else
        outfiles="$outfiles $1"
    fi

    # Shift all the parameters down by one
    shift

done

# put the message it the other arguments specified.

for i in $outfiles; do
    echo $message > $i
done

这个程序所做的是检查“-m”然后它会转移所有参数所以你有参数减去一次并将这个消息写入其他参数,例如 $./program.bash -m "Hello world" output1.txt ouput2.txt 该程序将消息“Hello world”放入新创建或(小心)覆盖的文件 output1.txt output2.txt

【讨论】:

  • 感谢您的信息!你会推荐使用什么来代替?任何我可以使用 aove 的地方 ./application
  • 更新了一个用于演示目的的小脚本。 @Jonathan 抱歉,我擦掉了你的拼写更正
【解决方案3】:
while getopts m: opt
do
     case "$opt" in
     (m) message="$OPTARG";;
     (*) echo "Usage: $0 [-m 'message'] [chan ...]" >&2; exit 1;;
     esac
done
shift $(($OPTIND-1))

for channel in "$@"
do
    whatever -y because -m "$message" $channel
done

应该可以。它使消息可选,并且不需要您指定任何渠道。您可以相当容易地添加更多选项(那些在字母后使用冒号指定参数的选项;那些不使用不带冒号的参数的选项)。您可以坚持 $# 在两个循环之间大于 0(但使用消息必须更改以反映这一点)。您可以坚持传递一条消息(但也必须为此更改使用消息)。所以它继续;你的选择很多。


如 cmets 中所述:

请注意,; 是 shell 的命令分隔符。你必须写:

./application 'channels;message'

在分号周围加上引号或在它之前加上反斜杠。这不是很正统的用法。您可以使用更惯用的符号,例如:

./application -m "this is a message" channel1 channel2 channel3

上面的脚本相当准确地实现了这个建议。

我看到的唯一问题是,如果消息中有" 字符怎么办。 ./application -m "this isn"t a message" channel1等等...

您需要了解 shell 元字符,包括 "'`$;(。对于所有这些,您需要逃脱罪魁祸首:

./application -m 'He said, "Don'\''t do that!"' chan1

通常,在消息周围使用单引号;如果要写单引号,请输入 '\''

./application -m 'He said, "This is a message."' chan1
./application -m "This isn't a message." chan2
./application -m 'He said, "This isn'\''t a message", but they disagreed." chan3

【讨论】:

    【解决方案4】:

    您可以使用cut 命令:

    #!/bin/bash 
    variables=`echo $* | cut -d';' -f1`
    message=`echo $* | cut -d';' -f2`
    echo "variables: " $variables
    echo "message: " $message
    

    一定要\-转义分号:

    $ ./application channels\;message
    channels:  channels
    message:  message
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2020-04-01
      • 2013-02-27
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多