0

I'm writing a little bash script for work. But now I'm stuck. Let me just show you the code and explain:

# I have an `array` with names
NAMES=(Skypper Lampart Shepard Ryan Dean Jensen)

Now I wanna iterate trough the names

for (( i = 0; i < 6; i++ )); do
    COMMAND="sed -i ${i+2}s/.*/${NAMES[${i}]}"
    ${COMMAND} config.txt
done

config.txt is a file with 2 numbers and names and I just wanna replace the names.

1
2
Name 1
Name 2
Name 3
Name 4
Name 5
Name 6

My problem is in the for-Loop how can I make $i + 2? So if I $i is 1 it should be 3.

Expected output:

1
2
Skypper
Lampart
Shepard
Ryan
Dean
Jensen
4
  • What is your expected output ? Commented Mar 28, 2017 at 8:25
  • @sat Added my expected output Commented Mar 28, 2017 at 8:27
  • 1
    I don't understand what is the inline file that sed is going to run the substitution on ? if you just want the numer $(($i + 2)) Commented Mar 28, 2017 at 8:31
  • @louigi600 Question is already answered, but ty! Commented Mar 28, 2017 at 8:34

5 Answers 5

1

If I understood what you want to accomplish (Replace "Name" with a string from NAMES array, problem being index in array starts from 0 and you want to start on the 3rd line) - dirty and quick solution is to add 2 empty strings to beginning of your array and start your loop from the position you want.

Sign up to request clarification or add additional context in comments.

3 Comments

No not the Array index just the number after -i because the names in the file start on line number 3.
Oh, in that case you need to look up bash arithmetic. I think it's ${(i + 2)} or ${((i+2))}, don't have access to bash right now.
Yeah it is $((${i} + 3))
1

Use this:

NAMES=(Skypper Lampart Shepard Ryan Dean Jensen)
line=2  # Need to skip first 2 lines
for name in "${NAMES[@]}"
do
    ((line++))
    sed -i "${line}s/.*/$name/g" config.txt
done

Comments

1

You can try something around like this:

NAMES=(Skypper Lampart Shepard Ryan Dean Jensen)
for (( i = 0; i < 6; i++ )); do
    b=$(( $i+2 ))
    COMMAND="sed -i $b s/.*/${NAMES[${i}]}"
    echo $COMMAND
#    ${COMMAND} config.txt
done

Which gives me something like the following output:

# sh test.sh 
sed -i 2 s/.*/Skypper
sed -i 3 s/.*/Lampart
sed -i 4 s/.*/Shepard
sed -i 5 s/.*/Ryan
sed -i 6 s/.*/Dean
sed -i 7 s/.*/Jensen

Comments

1

A bit late answer... :)

In your code you calling the sed n-times. This is inefficient. Therefore me proposing different solution, using ed instead of the sed. (as in good old times 30 years ago in BSD 2.9 :) ).

For this, approach:

  1. first creating commands for the ed
  2. executing them in one editor invocation
# it is good practice not using UPPERCASE variables
# as theycould collide with ENV variables

names=(Skypper Lampart Shepard Ryan Dean Jensen)
file="config.txt"

#create an array of commands for the "ed"
declare -a cmd
for name in "${names[@]}"; do
    cmd+=("/Name/s//$name/")
done
cmd+=(w q)

echo "=== [$file before] ==="
cat "$file"

echo "=== [commands for execution ]==="
printf "%s\n" "${cmd[@]}"

#execute the prepared command in the "ed"
printf "%s\n" "${cmd[@]}" | ed -s "$file"

echo "===[ $file after ]==="
cat "$file"

output from the above

=== [config.txt before] ===
1
2
Name 1
Name 2
Name 3
Name 4
Name 5
Name 6
=== [commands for execution ]===
/Name/s//Skypper/
/Name/s//Lampart/
/Name/s//Shepard/
/Name/s//Ryan/
/Name/s//Dean/
/Name/s//Jensen/
w
q
===[ config.txt after ]===
1
2
Skypper 1
Lampart 2
Shepard 3
Ryan 4
Dean 5
Jensen 6

a variant which replaces by the line-numbers

names=(Skypper Lampart Shepard Ryan Dean Jensen)
file="config.txt"

#create an array of commands for the "ed"
declare -a cmd
n=3
for name in "${names[@]}"; do
    cmd+=("${n}s/.*/$name/")
    let n++
done
cmd+=(w q)

echo "=== [$file before] ==="
cat "$file"

echo "=== [commands for execution ]==="
printf "%s\n" "${cmd[@]}"

#execute the prepared command in the "ed"
printf "%s\n" "${cmd[@]}" | ed -s "$file"

echo "===[ $file after ]==="
cat "$file"

output

=== [config.txt before] ===
1
2
Name 1
Name 2
Name 3
Name 4
Name 5
Name 6
=== [commands for execution ]===
3s/.*/Skypper/
4s/.*/Lampart/
5s/.*/Shepard/
6s/.*/Ryan/
7s/.*/Dean/
8s/.*/Jensen/
w
q
===[ config.txt after ]===
1
2
Skypper
Lampart
Shepard
Ryan
Dean
Jensen

2 Comments

First of all the Problem is in my case there isn't just the wor Name there are already different names :/ And secondly i didn't know ed.
@WasteD i created the answer to your question. In the question the input contains only Name strings, without mentioning anything other. It is trivial to modify my answer, but I sill don't know what input do you have...
0

Bash is good at reading arrays (something you could have easily searched for).

Try something like:

for idx in "${!NAMES[@]}"
do
  sed -i "$((idx + 2))s/.*/${NAMES[idx]} $idx/" config.txt
done

You will find that placing commands inside variables can also come unstuck unless you know what you are doing, so just use the command as intended :)

You might also need to remember that indexes start at zero and not 1

4 Comments

The Problem is not the Array but I the solution to my question is this $((idx + 2))
One more problem is, If idx is 3 then 3+2 = 5. It will lead to wrong line in sed.
Yeah in my script I have a for (( i = 0; i < 6; i++ )) and the sed is now sed -i $((${i} + 3))s/.*/${DATA[${i}]} and it works ty!
As in example, no need for ${} in either (()) or []. Another thought is that if you are renaming all the names and know the first 2 lines are all you need from the original file, you could just recreate the file anyway

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.