Cédric Dirr
Cédric Dirr

Reputation: 19

Issue using sed into a loop

Problem Description: I am trying to read the file test.csv, and add a variable $lastid (let's say 35 for the example) at the end of each line. But this variable needs to be incremented every two lines.

Expectations: I am expecting to get: for line 1 and 2 ",36" at the end of the line. for line 3-4 ",37" at the end of the line. for line 5-6 ",38" at the end of the line. and so on...

Script Code:

set -x ##debug mode on
lines=$( wc -l < test.csv ) ## you count the total of lines
lines=$((lines+1)) ## you increment it
g=$lastid   ## this is the variable of my lastid_game from my database (let's say 35 for the example)
i=1
j=1
while [ $j -le $lines ] ## while my lines number is lower or equal than the total of lines
do
    if [ $(( $j%2 )) -eq 0 ] ## if my line number is even
    then
        echo "number "$j" is even" ## I display it
        j=$(( $j+1 )) ## I increment my lines
        sed -e "s/$/,$g/" test.csv > test1.csv
    else
        echo "number "$j" is odd" ## I display my line is odd
        g=$(( $g+1 )) ## I increment my id_game
        j=$(( $j+1 )) ## I increment my lines
        sed -e "s/$/,$g/" test.csv > test1.csv
    fi
done
set +x ##debug mode off

Content of test.csv:

a,b,c,d,e,f
a,b,c,d,e,f
a,b,c,d,e,f
a,b,c,d,e,f
a,b,c,d,e,f
a,b,c,d,e,f
a,b,c,d,e,f
a,b,c,d,e,f

Current Output: ( which I believe is doing good)

++ wc -l
+ lines=46
+ lines=47
+ g=35
+ i=1
+ j=1
+ '[' 1 -le 47 ']'
+ '[' 1 -eq 0 ']'
+ echo 'number 1 is odd'
number 1 is odd
+ g=36
+ j=2
+ sed -e 's/$/,36/' test.csv
+ '[' 2 -le 47 ']'
+ '[' 0 -eq 0 ']'
+ echo 'number 2 is even'
number 2 is even
+ j=3
+ sed -e 's/$/,36/' test.csv
+ '[' 3 -le 47 ']'
+ '[' 1 -eq 0 ']'
+ echo 'number 3 is odd'
number 3 is odd
+ g=37
+ j=4
+ sed -e 's/$/,37/' test.csv
+ '[' 4 -le 47 ']'
+ '[' 0 -eq 0 ']'
+ echo 'number 4 is even'
number 4 is even
+ j=5
+ sed -e 's/$/,37/' test.csv
+ '[' 5 -le 47 ']'
+ '[' 1 -eq 0 ']'
+ echo 'number 5 is odd'
number 5 is odd
+ g=38
+ j=6
+ sed -e 's/$/,38/' test.csv
+ '[' 6 -le 47 ']'
+ '[' 0 -eq 0 ']'
+ echo 'number 6 is even'
number 6 is even
+ j=7
+ sed -e 's/$/,38/' test.csv
+ '[' 7 -le 47 ']'
+ '[' 1 -eq 0 ']'
+ echo 'number 7 is odd'

Current Result: test1.csv gives me the following result:

,59a,b,c,d,e,f
,59a,b,c,d,e,f
,59a,b,c,d,e,f
,59a,b,c,d,e,f
,59a,b,c,d,e,f
,59a,b,c,d,e,f
,59a,b,c,d,e,f
a,b,c,d,e,f,59

Problem 1: The id is always the same.

Problem 2: The id does not get incremented but seems to only display the last one calculated.

Does anyone has an idea what could be possibly wrong please?

Upvotes: 1

Views: 86

Answers (4)

agc
agc

Reputation: 8406

  1. Using GNU seq, paste, wc, and some shell arithmetic with a bit of fudging to make up for floating point round-off error:

    n=35; seq -f '%.0f' $n.9 .5 $(($n + $(wc -l < test.csv)/2 )).5 | 
    paste -d , test.csv -
    
  2. Using jot, paste, & wc:

    n=36 p=$(wc -l < test.csv) ; jot  $p $n $((p+n)) .499999999 |
    paste -d , test.csv -
    

Output of either:

a,b,c,d,e,f,36
a,b,c,d,e,f,36
a,b,c,d,e,f,37
a,b,c,d,e,f,37
a,b,c,d,e,f,38
a,b,c,d,e,f,38
a,b,c,d,e,f,39
a,b,c,d,e,f,39

Upvotes: 0

potong
potong

Reputation: 58400

This might work for you (GNU sed):

var=36
sed '1{x;s/^/'$var'/;x};                   # prime the counter
     1~2,+1{G;s/\n/,/};                    # append the counter
     2~2{x;s/.*/expr & + 1/e;x}' file      # increment the counter

The address range 1~2,+1 means 1 step 2 plus 1 or every two lines starting at line 1.

The address 2~2 means 2 step 2 or every second line starting at 2.

The RHS of the last substitution uses the command expr to increment the stored variable by means of the e flag which evaluates the expression.

Upvotes: 1

RavinderSingh13
RavinderSingh13

Reputation: 133508

Could you please try following.

val="35"  ##shell variable.
awk -v var="$val" 'BEGIN{FS=OFS=","} FNR%2!=0{++var} {$(NF+1)=var} 1' Input_file

Explanation: Adding detailed explanation for above.

awk -v var="$val" '      ##Starting awk program from here and creating awk variable var which has val in it.
BEGIN{                   ##Starting BEGIN section of awk program from here.
  FS=OFS=","             ##Setting field and output field separator as comma here.
}
FNR%2!=0{                ##Checking condition if line is odd line number wise then do following.
  ++var                  ##increase value of var with 1 here.
}
{
  $(NF+1)=var            ##Adding 1 more field which has var field in it for current line.
}
1                        ##1 will print current line here.                        
' Input_file             ##Mentioning Input_file name here.

Upvotes: 3

KamilCuk
KamilCuk

Reputation: 141000

It's typicall to use awk to parse files:

awk '{print $0 "," 36+int((NR-1)/2)}'
  • NR - current line number, starts with 1
  • (NR-1)/2 - calculate number from current line number. So a sequence of numbers like: {0, 0.5, 1, 1.5, 2, 2.5, ....etc.} for each line number
  • int(...) - round down to integers
  • 36+ you wanted to start with 36
  • $0 current line
  • "," add a comma between the number and current line

Notes:

  • sed -e "s/$/,$g/" test.csv > test1.csv is overwriting the same file over and over again for each loop
  • bash has arithmetic expansion, with that you can do if ((j <= lines)); then for clearer code.

Upvotes: 4

Related Questions