如何更新 bash 文件中的多字符分隔符字段?

How to update a multichracter delimited field in a file in bash?

我正在尝试匹配某个字段并从以多个字符分隔的文件中更新其数据。我正在使用它来模仿 SQL 的更新。这是使用 bash.

创建迷你 DBMS 的更大项目的一部分

我试过的:

sed "s/\^\_\^/:/g" $file_path | cut -d: -f1 | grep -nw SAR | sed "s/\^\_\^/:/g" | cut -d: -f2 | sed -i "s/$match/$update/g"

我的问题是我无法使用 sed -i 仅更新找到的这些特定列,因为您无法通过管道输入它。

正在使用的分隔符是:^_^

数据文件示例:

'EGP'^_^'Egypt'
'SAR'^_^'Europe'
'SAR'^_^'Europe'
'SAR'^_^'Europe'
'SAR'^_^'Europe'
'Europe'^_^'SAR'
'SAR'^_^'Europe'
'MYR'^_^'Malaysia'
'MYR'^_^'Malasia'
例如,

我的 $match 可以是 SAR,而 $update 可以是 USD

数据文件的预期更改

'EGP'^_^'Egypt'
'USD'^_^'Europe'
'USD'^_^'Europe'
'USD'^_^'Europe'
'USD'^_^'Europe'
'Europe'^_^'SAR'
'USD'^_^'Europe'
'MYR'^_^'Malaysia'
'MYR'^_^'Malasia'

如果有更好的不同方法,那也很受欢迎,因为我对 bash 脚本编写还很陌生。

最好在此处使用 awk

awk -v s="'SAR'" -v q="'USD'" -F'\^_\^' -v OFS='^_^' '==s {=q} 1' file

'EGP'^_^'Egypt'
'USD'^_^'Europe'
'USD'^_^'Europe'
'USD'^_^'Europe'
'USD'^_^'Europe'
'Europe'^_^'SAR'
'USD'^_^'Europe'
'MYR'^_^'Malaysia'
'MYR'^_^'Malasia'

解释:

  • -v s="'SAR'" 设置命令行变量 s='SAR'
  • -v q="'USD'" 设置命令行变量 s='USD'
  • -F '\^_\^' 将输入字段分隔符设置为 ^_^。我们需要对 ^ 进行转义,因为这是一个特殊的正则表达式元字符,我们需要对它进行双重转义,因为我们在稍后转换为正则表达式(字段分隔符)的字符串中使用它。
  • -v OFS='^_^' 将输出字段分隔符设置为 ^_^
  • == s 将第一个字段与 'SAR'
  • 进行比较
  • = q</code> 设置为变量 <code>'USD'

使用 sed,您可以在字符串 ^ 的开头使用 $match,并将其更改为 $update:

match="'SAR'"
update="'USD'"
sed "s/^$match\^_\^/$update^_^/" file

输出

'EGP'^_^'Egypt'
'USD'^_^'Europe'
'USD'^_^'Europe'
'USD'^_^'Europe'
'USD'^_^'Europe'
'Europe'^_^'SAR'
'USD'^_^'Europe'
'MYR'^_^'Malaysia'
'MYR'^_^'Malasia'

看到一个bash demo

使用您展示的示例,请尝试执行以下 awk 程序。

awk -v matchvalue="'SAR'" -v updatedvalue="'USD'" '
match([=10=],"^"matchvalue"\^_\^"){
  print updatedvalue"^_^" substr([=10=],RSTART+RLENGTH)
  next
}
1
'  Input_file

解释: 创建 2 个名为 matchvalueupdatedvalue 的变量以及 'SAR''USD' 样本中 OP 显示的值。然后在主程序中使用 match 函数匹配如果一行以 'SAR'^_^ 开头然后在其位置打印新值然后打印该行的其余部分,如果行不是从 'SAR'^_^ 开始然后简单地打印出来。

这是我最后做的:

escaped_delm=$(echo $curr_delim | sed 's/[^^\]/[&]/g; s/\^/\^/g; s/\/\\/g')
awk -F"$escaped_delm" -v a_col_update=$update_field -v pick=$p_tmp_field -v a_del="$match" -v a_ins="$insert" -v OFS="$curr_delim" '$pick==a_del {$a_col_update=a_ins} 1' $t_path > tmp && mv tmp $t_path

我面临的最大问题是我将定界符 ^_^ 作为变量传递给 awk。我的脚本假定我不知道变量是什么,并且它是在脚本开头传递给它的。这会导致问题,就像第一个答案建议 awk-F 选项认为 ^ 是一个正则表达式参数。

这就是我使用的 sed 命令非常方便的地方!它通过转义任何正则表达式元字符来清理分隔符。感谢 Ed Morton 对 的出色回答,我从中获得了 sed 命令。

希望其他人觉得这有用!

我的 awk 变量是:

  1. curr_delim="^_^"
  2. a_col_update=<column number to be updated>
  3. pick=<column used to pick the record/row>
  4. a_del=<field to be updated from picked record/row>
  5. a_ins=<new value for the picked field>
  6. OFS="$curr_delim"