hazelnut
hazelnut

Reputation: 15

Sed : loop on an array of string

In a bash script I would like to loop on an array and execute a sed command each times. Basically, I would like to do something like that :

names=( "Peter" "Juan Carlos" "Emily")  

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

What do I miss ?

EDIT : I explain further my intention:

My source is a tex document with lines like :

\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}

In fine, I'd like to have a .csv document formated like

"Peter";"You won!
"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."

Thanks for your answers !

Upvotes: 0

Views: 5677

Answers (3)

tripleee
tripleee

Reputation: 189457

While your question is a legitimate one, looping over the actor names is an extremely inefficient approach to your stated problem. Perhaps accept an answer which solves your original question, but then start over with something like this instead.

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

This will split each input line on curly braces, and calculate each line's index relative to the previous instance of \begin{cue}. If it is one, the second field is saved for later. If it is two, the saved value and the current line's second field are printed.

The same logic could be implemented in sed, but the field-oriented nature of Awk, along with the fact that it is somewhat more human readable than sed, makes it a natural choice for this particular task.

If your input file is more complex than your example leads us to understand, you might want to move to a higher-level language such as Python or Perl, and write a proper parser for it. With the correct libraries, it doesn't have to get a lot more complex than this Awk example.

Upvotes: 0

Simon
Simon

Reputation: 10841

I'm not completely sure what you're doing, but some diagnostic information might help you. If I try the script:

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

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

... on the file test.txt:

    Peter
Carlos
Simon

... I get the output:

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

... which shows you that the script is looping once for each word in names. Is that what you intend?

What I guess you may be looking for is this:

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

... which gives the output as follows:

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

... i.e. the name that is looped on has its preceding blanks removed, if that name is found in the input file.

Upvotes: 1

konsolebox
konsolebox

Reputation: 75498

Perhaps this is what you actually intend to do:

#!/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

Run with bash script.sh.

Upvotes: 1

Related Questions