【问题标题】:Changing variable in function dependant on getopts flag bash根据getopts标志bash更改函数中的变量
【发布时间】:2021-02-08 17:04:04
【问题描述】:

我有一个 bash 脚本,它可以查找连接的设备并将串行端口输出记录到文件中。 我正在使用 getopts 来选择记录的方法。 除了一行之外,其中两个功能相同。 我想将其更改为具有不同单行变量的单个函数(我的尝试如下)但没有成功。我怎样才能用 getopts 做到这一点? 非常感谢。

#!/bin/bash
#script to capture camera serial port logs via usb or UART.

file_name='DashcamLog'
#Date e.g: 20210204T120159 (ISO 8601)
current_date=$(date +%Y%m%dT%H%M%S)
BAUDRATE='115200'
#change to reflect udev rules e.g /dev/h1*
BOARDS=(/dev/ttyUSB* /dev/ttyACM*)
screen="$(screen -Sdm $port_name -L -Logfile $new_file_name $i $BAUDRATE)"
minicom="$(screen -Sdm ${port_name} minicom -b ${BAUDRATE} -D ${i} -C ${new_file_name})"

usage() {
    echo "Usage:"
    echo "Use $0 -a to use GNU screen to automatically capture logs on USB plug in"
    echo "Use $0 -s to use GNU screen to capture logs WITHOUT automatic capture on USB plug in."
    echo "Use $0 -m to use minicom to capture logs WITHOUT automatic capture on USB plug in."

}

#detects current + new devices + automatically starts logging
autoStartLog() {

    while true;do

        current_date=$(date +%Y%m%dT%H%M%S)

        for i in $BOARDS; do

            port_name=${i#/dev/}

            if ! screen -ls | grep -o $port_name > /dev/null;then
                (
                    serial_no="$(udevadm info --attribute-walk $i | grep -m 1 ATTRS{serial})"
                    #file name e.g = DashcamLog_20210208T094013_peri_h1p1.log
                    new_file_name="${file_name}_${current_date}_${HOSTNAME}_${port_name}.log"
                    $screen
                    echo $port_name 'serial_no: ' $serial_no $new_file_name
                )
            fi

        done

    done

}

#detects current devices + starts logging using screen(-s)/minicom(-m)
startLog() {

    for i in $BOARDS; do
        (
            port_name=${i#/dev/}
            serial_no="$(udevadm info --attribute-walk $i | grep -m 1 ATTRS{serial})"
            new_file_name="${file_name}_${current_date}_${HOSTNAME}_${port_name}.log"
            $1
            echo $port_name 'serial_no: ' $serial_no $new_file_name
        )
    done

}


while getopts ":hmsa" opt; do
    case ${opt} in
        h)
          usage
          ;;

        a)
          autoStartLog
          ;;

        s)
          startLog $screen
          ;;

        m)
          startLog $minicom
          ;;

        \? )
          echo "Invalid Option: -$OPTARG" 1>&2
          usage
          exit 1
          ;;
    esac
done
shift $((OPTIND -1))

【问题讨论】:

  • 哪一行?如果我查看 autoStartlog 和 startLog,它们不同于 1 行。我们需要详细信息才能理解您的问题。是 autoStartLog 中的 while true 吗?如果是这样,您可以创建一个执行处理的第三个函数。在 autoStartLog 中,执行while 并调用第三个函数。在startLog 中,您只需调用第三个函数一次。仅供参考,您的iffor 块周围不需要( )dodone 就足够了。
  • 感谢您的快速回复和有关括号的提示。我试图在 startLog 中更改$1,以便根据选择的选项开始使用不同的方法进行记录,例如。 ./log.sh -s 调用 startLog 并使用 screen 进行记录,./log.sh -m 调用 startLog 并使用 minicom 进行记录。

标签: bash shell sh getopts


【解决方案1】:

我改变了一些东西,因为我意识到在 cmets 中解释所有的小细节会太长。

代码如下:

#!/bin/bash

#script to capture camera serial port logs via usb or UART.

file_name='DashcamLog'
#Date e.g: 20210204T120159 (ISO 8601)
current_date=$(date +%Y%m%dT%H%M%S)
BAUDRATE='115200'
#change to reflect udev rules e.g /dev/h1*
BOARDS=(/dev/ttyUSB* /dev/ttyACM*)

usage()
{
    echo "Usage:"
    echo "Use $0 -a to use GNU screen to automatically capture logs on USB plug in"
    echo "Use $0 -s to use GNU screen to capture logs WITHOUT automatic capture on USB plug in."
    echo "Use $0 -m to use minicom to capture logs WITHOUT automatic capture on USB plug in."
    exit 1
}

#detects current devices + starts logging using screen(-s)/minicom(-m)
startLog()
{
    for i in "${BOARDS[@]}"
    do
        port_name="${i#/dev/}"
        serial_no=$(udevadm info --attribute-walk "$i" | grep -m 1 "ATTRS{serial}")
        new_file_name="${file_name}_${current_date}_${HOSTNAME}_${port_name}.log"
        case "$1" in
            "screen")
                echo "PUT THE SCREEN COMMAND HERE"
                ;;
            "minicom")
                echo "PUT THE MINICOM COMMAND HERE"
                ;;
            \?)
                echo "Invalid Option: -$OPTARG" 1>&2
                usage
                ;;
        esac
        echo "$port_name serial_no:  $serial_no $new_file_name"
    done
}

while getopts ":hms" opt
do
    case "$opt" in
        h)
            usage
            ;;
        s)
            startLog screen
            ;;
        m)
            startLog minicom
            ;;
        \?)
            echo "Invalid Option: -$OPTARG" 1>&2
            usage
            ;;
    esac
done
shift $((OPTIND -1))

详情:

  • 当您定义变量 screen 和 minicom 时,您有 "$( ... )"$() 中的命令会立即执行,而不是稍后在您稍后输入$1 时执行。这就是为什么我删除了那部分并将命令直接放在函数中。
  • 在 startLog() 中,我重用了 case。也可以使用if
  • BOARDS 是一个数组。所以当你做$BOARDS 时,没有指定索引,你只会得到第一项。您必须通过${BOARDS[@]} 处理所有项目。
  • 如果您不知道,BOARDS=(/dev/ttyUSB* /dev/ttyACM*) 将扩展 *,因此 BOARDS 将定义为所有文件 /dev/ttyUSB* 和所有文件 /dev/ttyACM*。它不会“留在”*
  • 当您从另一个命令 (var=$(command)) 定义变量时,您不需要在其周围加上 " "。这也很令人困惑,因为您应该在 $() 内用双引号括起变量,因此您会在其他双引号内使用双引号。

我也把它放在我喜欢的代码风格中,但那是灵活的,受个人喜好的影响。

您可以将代码放入https://www.shellcheck.net/ 以验证语法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多