【问题标题】:Splitting script with getops bash script使用 getopts bash 脚本拆分脚本
【发布时间】:2017-04-06 13:00:05
【问题描述】:

我正在尝试使用带有 getops 的选项来拆分代码,本质上,如果设置了 1 个选项,我希望运行 1 个脚本,如果设置了另一个选项,则运行另一个脚本,请参见代码:

#!/bin/bash

# A POSIX variable
OPTIND=1         # Reset in case getopts has been used previously in the shell.

# Initialize our own variables:
1=""
2=""
verbose=0


while getopts "h?v:f:m:l:" opt; do
    case "$opt" in
    h|\?)
        exit 0
        ;;
    v)  verbose=1
        ;;
    f)  1=$OPTARG
        ;;
    m)  2=$OPTARG
        ;;
    esac
done

for file in $1;
do
        1="$(sed '1d' $1 | awk -F \" '{print $2}')"
        printf "$1\n"
done <"$1"

for file in $2;
do
        2="$(awk '{print $1}' $2 | sort | uniq)"
        printf "$2\n"
done <"$2"  

所以在我的代码中,如果选项 -f 设置了一个文件,那么我会运行以“for file in $1”开头的 for 循环。如果 -m 设置了一个文件,我会运行以“for file in $2”开头的循环。

我也想让它只有 -m 或 -f 可以运行,即不能同时运行。

命令行用法是:./script.sh -f file.txt or ./script.sh -m file.txt

我该如何设置? (也接受 getops 以外的其他选项)

-f 的示例文件:

<blank line>
"b2f5ff47436671b6e533d8dc3614845d","54fd1711209fb1c0781092374132c66e79e2241b","path/path","output"
"8fa14cdd754f91cc6554c9e71929cce7","4a0a19218e082a343a1b17e5333409af9d98f0f5","path/path2","output2"
"2510c39011c5be704182423e3a695e91","27d5482eebd075de44389774fce28c69f45c8a75","path/path3","output3"
...

-m 的示例文件:

b2f5ff47436671b6e533d8dc3614845d /paths/path
2510c39011c5be704182423e3a695e91 /paths/path2

我正在使用 awk 提取 -f 和 -m 文件的第一个字段。 sed 命令在提取第一个字段之前删除文件的第一行 ()。

预期输出:

b2f5ff47436671b6e533d8dc3614845d
8fa14cdd754f91cc6554c9e71929cce7
2510c39011c5be704182423e3a695e91
b2f5ff47436671b6e533d8dc3614845d
2510c39011c5be704182423e3a695e91

然后我可以使用它来匹配哈希列表文件。

【问题讨论】:

  • 在所有可能的变量名中,bash中是否必须使用12,作为$1$2时有特殊含义?
  • 我使用 1 和 2 来尝试显示脚本 1 和脚本 2,而不是出于任何其他原因,因此可以在必要时更改变量名称
  • 你的命令行参数是什么,请在上面提到!
  • 用法是./script.sh -f file.txt or ./script.sh -m file.txt
  • 所以你基本上的意思是,对于 -f 选项使用sed-m 使用awk,你在for file in $1; do...&lt;"$1" 中尝试做什么也不正确

标签: bash


【解决方案1】:

假设两个文件的内容如下,

cat file1

"b2f5ff47436671b6e533d8dc3614845d","54fd1711209fb1c0781092374132c66e79e2241b","path/path","output"
"8fa14cdd754f91cc6554c9e71929cce7","4a0a19218e082a343a1b17e5333409af9d98f0f5","path/path2","output2"
"2510c39011c5be704182423e3a695e91","27d5482eebd075de44389774fce28c69f45c8a75","path/path3","output3"

另一个文件是,

cat file2
b2f5ff47436671b6e533d8dc3614845d /paths/path
2510c39011c5be704182423e3a695e91 /paths/path2

您可以使用单个Awk 作为

awk 'FNR==NR && NF{gsub(/"/,"",$1); uniqueString[NR]=$1; next}{uniqueString[NR]=$1; next}END{for (i in uniqueString) print uniqueString[i]}' FS="," file1 FS=" " file2

给了

b2f5ff47436671b6e533d8dc3614845d
8fa14cdd754f91cc6554c9e71929cce7
2510c39011c5be704182423e3a695e91
b2f5ff47436671b6e533d8dc3614845d
2510c39011c5be704182423e3a695e91

awk的核心逻辑是通过NR创建一个数组uniqueString索引; awk 中的一个特殊变量,它在文件中处理每一行时跟踪行号

FNR==NR 将第一个存储在 $1 中的条目的文件解析为哈希映射。由于值包含双引号,因此使用gsub() 将其删除,并且字段拆分FS 由字段, 完成。

file1 中解析完所有行后,将在第二个文件file2 上执行以下{..} 部分,再次将$1 的条目存储在数组中,但现在字段分隔符设置为白色-空间。

处理完所有行后,使用END子句打印解析的行。

【讨论】: