如何重构简单的脚本以使其可通过管道传输(从标准输出获取输入)

如何重构简单的脚本以使其可通过管道传输(从标准输出获取输入)

我有以下脚本:

#!/bin/bash

file=$1

echo "Phone:" 
read phone
echo
echo "Column:"
read column
echo
echo "New Value:"
read value
echo

index=$(cat $file | grep -n $phone | cut -d: -f1)

cat "$file" | awk -v idx="$index" -v col="$column" -v value="$value" -F ',' '{if (NR==idx) {for(i=1;i<=NF;i++) {if (i==col) $i=value; printf("%s%s", $i, (i==NF ? "\n":FS))}} else print}'

echo

exit 0

它接收一个文件,并提示用户输入数字、列和新值,然后更新该特定字段。我的问题是,我必须这样称呼它:

./update.sh data.csv

我希望能够将脚本转换为别名,并能够使用标志对其进行管道传输,而不是提示用户输入值,因此添加自定义标志(-c 表示列,-v 表示值,-e 表示过滤的模式),例如:

cat data.csv | update -c 2 -v "value" -e "pattern"

有人可以指导我如何将脚本转换为带有标志的别名吗? (别名是指命令,也许我错误地使用了别名)

另外,我仍在学习bash、awk和linux,如果你发现我做错了什么或效率低下,请纠正我。

提前致谢

ps 也许有帮助,data.csv 如下所示:

444-555-7777, Max,Weaver, personal:friend:musician
111-222-6665, Craig,Kowalick,office:friend
888-797-2345,Tom, O’Brien, personal:family:musician:midnightsociety

答案1

使用获取选择解析参数,然后awk或类似地匹配 CSV 字段,例如(未经测试):

#!/usr/bin/env bash

while getopts ":p:c:v:e:" arg; do
    case $arg in
        p) phone=$OPTARG ;;
        c) col=$OPTARG ;;
        v) val=$OPTARG ;;
        e) ere=$OPTARG ;;
        *) printf 'Unknown argument "%s"\n' "$arg" >&2
           exit 1
           ;;
    esac
done
shift $((OPTIND-1))

然后使用 awk 用 CSV 做任何你想做的事情,例如(再次未经测试,只是一个例子,并不是为了做你真正想做的事情,上面的变量只是展示如何使用它们):

awk -v phone="$phone" -v col="$col" -v val="$val" -v ere="$ere" '
    BEGIN { FS=OFS="," }
    ($1 == phone) && ($0 ~ ere) && ($col == val) {
        print "Matched: " $0
    }
' "${@:--}"

"${@:--}"告诉 awk 从文件名中读取(如果有传入),否则读取 stdin。

您可能需要在 shell 脚本或 awk 脚本中添加一些代码,以验证是否填充了所有强制变量,然后再在 awk 脚本中使用它们,如上面所示。您可以在 getopts 循环和 awk 调用之间添加如下 shell 代码:

while [[ -z "$phone" ]]; do
    echo "Phone:" 
    read -r phone
done

确保变量由提示+响应填充(如果尚未从命令行设置)。

我在上面假设您的问题中的“模式”您想要进行全行扩展正则表达式匹配,这就是为什么我将关联变量命名erepat或 类似的原因。我知道这是违反直觉的,但在陈述您的要求或编写模式匹配代码时不要使用“模式”一词。这是非常模糊的,就像去汽车经销店只告诉推销员你想买一辆“汽车”。具体说明您想要在什么上下文中匹配哪种模式,请参阅如何找到与模式匹配的文本

相关内容