You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将含sed参数的变量转换为数组?适配bash4.4与sed4.4

Bash中兼容缩进格式的sed表达式数组简洁实现

使用环境

sed (GNU sed) 4.4
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

问题背景

在bash脚本中需要使用20余个复杂的sed -e表达式,例如将aa bb cc转换为aaBBcc,单行写法如下:

sed -e 's# ##g' -e 's#b#B#g' <<< "aa bb cc"

或者用数组形式管理参数:

k=('-e' 's# ##g'    '-e' 's#b#B#g'); sed "${k[@]}" <<< "aa bb cc"

为了提升可读性和可编辑性,我将这些参数以带空格、缩进的形式存入变量,示例如下:

#!/bin/bash
k="-e s#    #    #g \
   -e s# b  # B  #g \
  "

现有转换为数组的方法虽能运行,但流程繁琐,且无法支持带引号的表达式(比如-e 's#b#B#g')。需要更简洁的实现,且必须兼容当前带空格的变量格式。

实际场景示例(书签URL转换)

原始URL

https://www.ebay.com/sch/i.html?_from=R40&_trksid=123456&_nkw=%28vintage%2Cvtg%29+%28polartec%2Cfleece%29+%28full%2Czip%2Czips%2Czipper%2Czippered%2Czipping%29+-%28hilfiger%2C%22old+navy%22%2Chooded%2Ccamo%2Ccamouflage%2Cvest%2Csmall%2Cmedium%2Cxl%2Cxxl%2Chalf%2Cquarter%2C%221%2F4%22%2C%221%2F2%22%2C+lined%2Cwinnie%2Ctoddler%2Ckids%2Cladies%2Cwomens%2Cwomen%29&_sacat=11450&LH_TitleDesc=0&_odkw=%28vintage%2Cvtg%29+fleece+%28full%2Czip%2Czips%2Czipper%2Czippered%2Czipping%29+-%28hilfiger%2C%22old+navy%22%2Chooded%2Ccamo%2Ccamouflage%2Cvest%2Csmall%2Cmedium%2Cxl%2Cxxl%2Chalf%2Cquarter%2C%221%2F4%22%2C%221%2F2%22%2C+lined%2Cwinnie%2Ctoddler%2Ckids%2Cladies%2Cwomens%2Cwomen%29&_osacat=11450&_sop=10&LH_PrefLoc=3&_ipg=240&_udhi=99

转换后URL

https://www.ebay.com/sch/i.html?&_nkw=(vintage,vtg)+(polartec,fleece)+(full,zip,zips,zipper,zippered,zipping)+-(hilfiger,old+navy,hooded,camo,camouflage,vest,small,medium,xl,xxl,half,quarter,1/4,1/2,+lined,winnie,toddler,kids,ladies,womens,women)&_sacat=1145011450&_sop=10&LH_PrefLoc=3&_udhi=99&_ipg=240

当前脚本

#!/bin/bash
echo
k="-e s# [&]*_from=R40      #            #   \
   -e s# [&]*_trk[^&]*      #            #   \
   -e s# [&]*_odkw[^&]*     #            #   \
   -e s# [&]*_osacat[^&]    #            #   \
   -e s# [&]*_sacat=0       #            #   \
   -e s# [&]*LH_TitleDesc=0 #            #   \
   -e s# ++                 # +          #g  \
   -e s# %2F                # /          #g  \
   -e s# %28                # (          #g  \
   -e s# %29                # )          #g  \
   -e s# %2C                # ,          #g  \
   -e s# %22                #            #g  \
   -e s# &_ipg=[0-9]*       #            #   \
   -e s# $                  # \&_ipg=240 #   \
   "
k=$(sed -e 's# ##g'         \
        -e 's|###|# ##|g'   \
        -e 's#-e#|-e #g'    \
        -e 's#|##'          \
        <<< "$k"            \
   )
z=$IFS; IFS="|"; k=($k); IFS=$z        
sed "${k[@]}" <<< "$1"

简洁实现方案

方案1:无引号表达式的高效处理

如果不需要带引号的表达式,可通过sed预处理变量后用readarray生成数组,流程更简洁:

#!/bin/bash
k="-e s# [&]*_from=R40      #            #   \
   -e s# [&]*_trk[^&]*      #            #   \
   -e s# [&]*_odkw[^&]*     #            #   \
   -e s# [&]*_osacat[^&]    #            #   \
   -e s# [&]*_sacat=0       #            #   \
   -e s# [&]*LH_TitleDesc=0 #            #   \
   -e s# ++                 # +          #g  \
   -e s# %2F                # /          #g  \
   -e s# %28                # (          #g  \
   -e s# %29                # )          #g  \
   -e s# %2C                # ,          #g  \
   -e s# %22                #            #g  \
   -e s# &_ipg=[0-9]*       #            #   \
   -e s# $                  # \&_ipg=240 #   \
   "

# 预处理:去掉缩进、多余空格,拆分每个-e表达式为独立行
processed=$(sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; s/[[:space:]]+#/#/g' <<< "$k" | tr '\n' ' ' | sed -E 's/ -e /\n-e /g')

# 将处理后的内容读入数组
readarray -t sed_args < <(echo "$processed")

# 执行sed转换
sed "${sed_args[@]}" <<< "$1"

方案2:支持带引号表达式的兼容处理

如果需要使用带引号的表达式(比如-e 's#b#B#g'),可通过eval安全构造数组,完美兼容原有缩进格式:

#!/bin/bash
k="-e 's# [&]*_from=R40      #            #'   \
   -e 's# [&]*_trk[^&]*      #            #'   \
   -e 's# ++                 # +          #g'  \
   -e 's# %2F                # /          #g'  \
   -e 's# %28                # (          #g'  \
   -e 's# %29                # )          #g'  \
   -e 's# %2C                # ,          #g'  \
   -e 's# %22                #            #g'  \
   -e 's# &_ipg=[0-9]*       #            #'   \
   -e 's# $                  # \&_ipg=240 #'   \
   "

# 生成数组定义字符串:去掉缩进和换行
array_def="sed_args=($(sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' <<< "$k" | tr '\n' ' '))"

# 执行数组定义
eval "$array_def"

# 执行sed转换
sed "${sed_args[@]}" <<< "$1"

这两种方案都保留了原变量的缩进格式,提升了可读性,同时解决了原方法流程复杂、不支持带引号表达式的问题。

内容的提问来源于stack exchange,提问作者Will

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 03:45:41