如何在Shell脚本中用数组复用逻辑处理YAML视图与表数据
问题描述
我写了一个Shell脚本用来读取YAML文件并做数据处理,YAML文件结构如下:
view: schema1.view1:/some-path/view1.sql schema2.view2:/some-path/view2.sql tables: schema1.table1:/some-path/table1.sql schema2.table2:/some-path/table2.sql end
期望输出格式为:
schema:schema1 object:view1 fileloc:/some-path/view1.sql schema:schema2 object:view2 fileloc:/some-path/view2.sql schema:schema1 object:table1 fileloc:/some-path/table1.sql schema:schema2 object:table2 fileloc:/some-path/table2.sql
当前我用以下Shell代码读取YAML文件:
#!/bin/bash input=./file.yaml viewData=$(sed '/view/,/tables/!d;/tables/q' $input|sed '1d;$d') tableData=$(sed '/tables/,/end/!d;/end/q' $input|sed '1d;$d')
其中viewData和tableData分别存储对应的数据。之后我用for循环处理table数据:
for line in $tableData; do field=`echo $line | cut -d: -f1` schema=`echo $field | cut -d. -f1` object=`echo $field | cut -d. -f2` fileLoc=`echo $line | cut -d: -f2` echo "schema=$schema" echo "object=$object" echo "fileloc=$fileLoc" done
但处理view数据时需要重复写相同逻辑,请问如何在Shell脚本中用数组或其他方式复用该循环逻辑,同时处理视图与表数据?
解决方案
方法1:封装处理逻辑为函数
把重复的循环逻辑封装成Shell函数,只需编写一次处理代码,分别传入viewData和tableData即可完成两类数据的处理。
修改后的完整脚本:
#!/bin/bash input=./file.yaml # 封装通用处理逻辑为函数 process_data() { local data="$1" for line in $data; do field=$(echo "$line" | cut -d: -f1) schema=$(echo "$field" | cut -d. -f1) object=$(echo "$field" | cut -d. -f2) # 用-f2-替代-f2,避免路径含冒号时被截断 fileLoc=$(echo "$line" | cut -d: -f2-) echo "schema:$schema" echo "object:$object" echo "fileloc:$fileLoc" echo # 空行分隔每个对象 done } # 提取视图和表的数据块 viewData=$(sed '/view/,/tables/!d;/tables/q' "$input" | sed '1d;$d') tableData=$(sed '/tables/,/end/!d;/end/q' "$input" | sed '1d;$d') # 调用函数处理两类数据 process_data "$viewData" process_data "$tableData"
方法2:用数组批量管理数据块
如果后续可能新增更多类似数据块(比如functions:),可以用关联数组存储数据块的起始/结束标记,遍历数组统一处理,扩展性更强。
示例脚本:
#!/bin/bash input=./file.yaml # 封装单条数据的处理函数 process_line() { local line="$1" field=$(echo "$line" | cut -d: -f1) schema=$(echo "$field" | cut -d. -f1) object=$(echo "$field" | cut -d. -f2) fileLoc=$(echo "$line" | cut -d: -f2-) echo "schema:$schema" echo "object:$object" echo "fileloc:$fileLoc" echo } # 定义数据块的起始标记和对应的结束标记 declare -A data_blocks=( ["view"]="tables" ["tables"]="end" ) # 遍历所有数据块处理 for block_start in "${!data_blocks[@]}"; do block_end=${data_blocks[$block_start]} # 提取当前数据块的内容 block_data=$(sed "/$block_start/,/$block_end/!d;/$block_end/q" "$input" | sed '1d;$d') # 处理数据块内的每一行 for line in $block_data; do process_line "$line" done done
新增数据块时,仅需在data_blocks数组中添加新的起始/结束标记对,无需修改处理逻辑。
内容的提问来源于stack exchange,提问作者Chuck
相关产品推荐
相关产品推荐

