【问题标题】:bash : run sed -i multiple timesbash:多次运行 sed -i
【发布时间】:2021-06-03 18:33:11
【问题描述】:

我有一个要在文件中替换的字符串列表。但是,当我运行sed -i(直接更改文件)时,只有最后一个替换有效。我认为最后一个会覆盖之前的所有更改?

#!/bin/bash

# echo "searching text to be replaced from csv file.."

mapfile -t searchArray < search
mapfile -t replacementArray < replacement
for file in *.txt;
do
echo ">>>processing $file.."
for idx in "${!searchArray[@]}"; do
echo "@@replacing ${searchArray[idx]}"  
    if [[ ${searchArray[idx]} != "" && ${replacementArray[idx]} != "" ]]; then        
    ESCAPED_REPLACE=$(printf '%s\n' "${searchArray[idx]}" | sed -e 's/[\/&]/\\&/g')
    sed -i "s/$ESCAPED_REPLACE/${replacementArray[idx]}/g" "$file"             
    fi        
 done
done

尝试像这样处理 sed 文件:

for idx in "${!searchArray[@]}"; do
    if [[ ${searchArray[idx]} != "" && ${replacementArray[idx]} != "" ]]; 
then        
        ESCAPED_REPLACE=$(printf '%s\n' "${searchArray[idx]}" | sed -e 
's/[\/&]/\\&/g')
        printf 's/%s/%s/g\n' "$ESCAPED_REPLACE" "${replacementArray[idx]}"
    fi 
done >script.sed

for file in *.txt;
do
sed -f script.sed "$file" >outputfile && mv outputfile "$file"  
done

但是搜索字符串有一些特殊字符,例如"${template(properties).activateDate}(pd -&gt; \"#dateFormatCalc('$pd', 'long', 'dd MMM yyyy','-12Q')\")",我怎样才能在*.sed 文件中转义这些特殊字符?我的意思是以编程方式生成 *.sed 文件。

编辑: 这是我的搜索文件(两行):search string

${template(properties).activateDate}(pd -> \"#dateFormatCalc('$pd', 'long',  'dd MMM yyyy','-12Q')\")
${template(properties).activateDate}(pd -> \"#dateFormatCalc('$pd', 'long', 'dd MMM yyyy','-16')\")

这是我的替换文件(两行):

#dateCalc('dd-mm-yyyy','end','-12','Q')
#dateCalc('dd-mm-yyyy','end','-16','Q')

这是我的测试文件(搜索和替换)。它是一个 JSON 文件: code sample pic

   {
       "type": "TEXTBOX",
       "type": "TEXTBOX",
       "label": "${template(properties).activateDate}(pd -> \"#dateFormatCalc('$pd', 'long', 'dd MMM yyyy','-12Q')\")",
       "value": "${template(properties).activateDate}(pd -> \"#dateFormatCalc('$pd', 'long', 'dd MMM yyyy','-12Q')\")",
       "format": "PERCENTAGE",
       "displayTotal": false,
       "deactivated": false
   }

预期的结果应该是这样的:

   {
       "type": "TEXTBOX",
       "type": "TEXTBOX",
       "label": "#dateCalc('dd-mm-yyyy','end','-12','Q')",
       "value": "#dateCalc('dd-mm-yyyy','end','-12','Q')",
       "format": "PERCENTAGE",
       "displayTotal": false,
       "deactivated": false
   }

【问题讨论】:

  • @tripleee 谢谢。是的,我正在处理 sed 文件,但 searchArray 中的搜索字符串有一些特殊字符。如何通过代码生成它?搜索字符串类似于“ ${template(properties).activateDate}(pd -> \"#dateFormatCalc('$pd', 'long', 'dd MMM yyyy','-12Q')\") ”
  • 您描述的症状似乎很难理解;您的代码本身看起来确实应该执行所有替换。您的输入文件中是否有 DOS 换行符?或者问题可能只是因为您忘记转义需要转义的内容(例如,未转义的 $ 与文字 $ 不匹配)。
  • 请不要编辑您的问题,以免现有答案不再有意义。您最初的尝试尝试循环运行sed -i,但现在我的回答看起来很奇怪,因为您取出了我正在评论的代码。
  • 我从未见过paste -d / 没有正确加入列的地方。您是否在某个 Busybox 或基于 DOS 的平台上?或者您的输入文件是否包含不可见的控制字符(可能是 DOS 换行符)?
  • 如果你的paste 真的坏了,你可以用paste &lt;(sed ...) &lt;(sed ...) 解决这个问题,并让随后的sed 脚本也将分隔制表符更改为斜线。

标签: bash sed replace


【解决方案1】:

在同一个文件上多次运行sed -i 是一种可怕的反模式。只需在同一个 sed 脚本中进行所有替换即可。

您需要转义比目前更多的元字符。有关详细信息,请参阅Escape a string for a sed replace pattern。可能这就是你的许多替换似乎不起作用的原因。

简单地说,试试这个:

# Escape metacharacters from both files and paste them side by side
paste -d / <(sed -e 's/[]%\/$*.^[]/\\&/g' search) <(sed -e 's/[\/&]/\\&/g' replace) |
# Add necessary decorations to turn this into a valid sed script
sed 's%^%s/%;s%$%/g%' |
# Now pass the generated sed script to another sed instance
sed -f - -i *.txt

您可以从流水线的末端剥离一些东西,看看每一步都在做什么。我鼓励您这样做以了解其工作原理。但简单地说,我们将pat.ternrepl&amp;acement 转换为pat\.tern/repl\&amp;acement,然后在其周围添加sed 命令,这样我们就得到s/pat\.tern/repl\&amp;acement/g;然后将其提供给sed -i

与往常一样,如果您的sed 不喜欢-f -,请尝试-f /dev/stdin,或者,在绝对最坏的情况下,将生成的文件保存到临时文件中(完成后不要忘记将其删除)。

【讨论】:

  • 未经测试;没有样本数据,很难知道预期或测试什么。
  • 更新了样本数据。你的解释很清楚。尝试但在粘贴步骤中被阻止; .运行:粘贴 -d /
  • 错了怎么办?您的示例 JSON 数据有一个换行符,可防止 sed 在任一示例搜索短语中找到匹配项,但生成的脚本看起来很好。
  • 为了说明,这里有一个演示,它适用于第二个搜索短语而不是第一个,只需从 JSON 示例中修剪换行符; ideone.com/BpYDMW
  • 文字图片几乎总是一个坏主意。见meta.stackoverflow.com/questions/303812/…
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 2015-01-22
  • 2021-01-10
  • 1970-01-01
  • 1970-01-01
  • 2013-11-25
  • 2018-12-15
  • 1970-01-01
相关资源
最近更新 更多