【问题标题】:Sed : loop on an array of stringSed : 在字符串数组上循环
【发布时间】:2013-09-01 20:14:17
【问题描述】:

在 bash 脚本中,我想在一个数组上循环并每次执行一个 sed 命令。 基本上,我想做这样的事情:

名称=(“彼得”“胡安卡洛斯”“艾米丽”) ${names[*]} 中的名称 做 sed 's/[[:space:]]*{'"$name"'}/'"$name"'/g' "$file" 完毕

我错过了什么?

编辑: 我进一步解释我的意图:

我的来源是一个 tex 文档,其中包含以下行:

\begin{cue}
    {Peter}           
    {You won !}
\end{cue}
\begin{cue}
    {Juan Carlos}           
    {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vitae ipsum hendrerit, gravida est eget, tincidunt sem. Maecenas dapibus nibh commodo, pulvinar lorem at, egestas leo.}
\end{cue}

没关系,我想要一个格式如下的 .csv 文档

“彼得”;“你赢了! “Juan Carlos”;“Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vitae ipsum hendrerit, gravida est eget, tincidunt sem. Maecenas dapibus nibh commodo, pulvinar lorem at, egestas leo。”

感谢您的回答!

【问题讨论】:

  • 我们不确定。你到底想做什么
  • 不知道你的目标是什么,但是看看你的 sed 脚本,我注意到你有很多不同类型的引号。您可能需要添加一些反斜杠。 sed "s/[[:space:]]*{'\"$name\"'}/ ...你明白了。
  • 另外sed 's/[[:space:]]*\(Peter\|Juan Carlos\|Emily\)/\1/g' "$file" 将在没有循环或重复输出的情况下执行此操作。

标签: bash sed


【解决方案1】:

我不完全确定您在做什么,但一些诊断信息可能会对您有所帮助。如果我尝试脚本:

names=( "Peter" "Juan Carlos" "Emily")
file=test.txt

for name in ${names[*]}     
do    
  echo ">>" $name
  sed 's/[[:space:]]*{'"$name"'}/'"$name"'/g' "$file"
done

...在文件test.txt:

    Peter
Carlos
Simon

...我得到输出:

>> Peter
    Peter
Carlos
Simon
>> Juan
    Peter
Carlos
Simon
>> Carlos
    Peter
Carlos
Simon
>> Emily
    Peter
Carlos
Simon

... 这表明脚本为names 中的每个单词循环一次。这是你的意图吗?

我猜你可能正在寻找的是:

names=( "Peter|Juan Carlos|Emily")
file=test.txt
IFS="|"
for name in ${names[*]}     
do    
  echo ">>"  $name
  sed -e"s/[[:space:]]*$name/$name/g" "$file"
done

... 输出如下:

>> Peter
Peter
Carlos
Simon
>> Juan Carlos
    Peter
Carlos
Simon
>> Emily
    Peter
Carlos
Simon

... 即,如果在输入文件中找到该名称,则循环的名称将删除其前面的空格。

【讨论】:

  • 您可以在循环中添加双引号,而不是更改 IFS:for name in "${names[@]}"
【解决方案2】:

也许这就是你真正想要做的:

#!/bin/bash

names=("Peter" "Juan Carlos" "Emily")
file="<your file's path here>"

expressions=()
template='s|[[:space:]]*{__NAME__}|__NAME__|g'

for __ in "${names[@]}"; do
    expressions+=(-e "${template//__NAME__/$__}")
done

sed "${expressions[@]}" -- "$file"  ## or sed -i ... to replace contents of file

使用bash script.sh 运行。

【讨论】:

    【解决方案3】:

    虽然您的问题是合法的,但遍历演员姓名对于您陈述的问题来说是一种极其低效的方法。也许接受一个可以解决您最初问题的答案,然后用类似的方法重新开始。

    awk -F '[{}]' '/^\\begin\{cue\}$/ { i=0;next }                                 
       ++i == 1 { actor=$2; next }                                                  
       i == 2 { printf "\"%s\";\"%s\"\n", actor, $2; next }' "$file"
    

    这将在花括号上分割每行输入,并计算每行相对于\begin{cue} 的前一个实例的索引。如果是一个,则保存第二个字段以备后用。如果是二,则打印保存的值和当前行的第二个字段。

    同样的逻辑可以在 sed 中实现,但是 Awk 面向字段的特性,以及它比 sed 更易于阅读的事实,使它成为这个特定任务的自然选择。

    如果您的输入文件比您的示例让我们理解的更复杂,您可能希望转向更高级别的语言,例如 Python 或 Perl,并为其编写适当的解析器。使用正确的库,它不必比这个 Awk 示例复杂得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-21
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2017-10-06
      • 1970-01-01
      相关资源
      最近更新 更多