noobroot
noobroot

Reputation: 15

if statement regex or bad echoing ? (bash 3.0)

could anyone tell me why this is happening? im trying to insert some lines before an occurrence of a given string, say...

thing
extern void hello_dude(char *loc, long length){
thing

to

thing
another
extern void hello_dude(char *loc, long length){
thing

with a simple (sigh) bash 3.0 script, the thing is that the if statement im using to match the string is echoing the line splitted like this:

thing
another
extern
void
hello_dude(char
*loc,
long
length){
thing

the statement is

elif [[ "$LINE" =~ *hello_dude\(* ]]; then
    echo "$LINE" >> temp2

theres obviously a leading if statement working OK before the elif.

Ive tried every quote flavor and regex i can imagine...

any help will be much appreciated

EDIT: this is the actual script im using

#!/bin/bash

for LINE in `(cat temp1)`
do
  if [[ "$LINE" = sendMessage4K* ]]; then
     echo '/*---RUAISI---*/' >> temp2
     echo "$LINE" >> temp2
   elif [[ "$LINE" =~ *alpha_display\(* ]]; then
     echo "$LINE" >> temp2
     echo '/*---RUAISI---*/' >> temp2
  else
     echo "$LINE" >> temp2
  fi
done

the temp1 file is:

FIX
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern void alpha_display(char *loc, long length){
  FIX
}
FIX

the idea is to get temp2 with:

FIX
/*---RUAISI---*/
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern void alpha_display(char *loc, long length){
/*---RUAISI---*/
  FIX
}
FIX

but im getting this

FIX
/*---RUAISI---*/
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern
void
alpha_display(char
/*---RUAISI---*/
*loc,
long
length){
FIX
}
FIX

Upvotes: 0

Views: 208

Answers (3)

larsks
larsks

Reputation: 311635

EDIT: Whoops, my answer mostly duplicates the one from choroba. I'm going to leave it here because I think it goes into a little more detail about the why of things, but you should probably accept choroba's.

Your problem is here:

for LINE in `(cat temp1)`

This splits up each line use IFS, so that given an input line like this:

extern void alpha_display

You get a for loop that looks something like this:

for LINE in extern void alpha_display; do

Which means that LINE is set to, in sequence:

  1. extern
  2. void
  3. alpha_display

To demonstrate this, try the following little script:

for LINE in `cat temp1`; do
  echo "$LINE"
done

If you really want to read a file line-by-line, you're better off using read in a while loop with input redirected from your souce file. Compare the output of the following to what the previous script produces:

while read LINE; do
  echo "$LINE"
done < temp1

With this in mind, you can fix your script like this:

while read LINE; do
  if [[ "$LINE" = sendMessage4K* ]]; then
     echo '/*---RUAISI---*/' >> temp2
   elif [[ "$LINE" = *alpha_display\(* ]]; then
     echo '/*---RUAISI---*/' >> temp2
   fi

   echo "$LINE" >> temp2
done < temp1

Notice that in addition to using a while loop, I've also removed the regular expression operator from the elif expression (because, as has previously been pointed out, you were using glob expressions rather than regular expressions), and I've eliminated some redunant code.

This script produces the following output:

FIX
/*---RUAISI---*/
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern void alpha_display(char *loc, long length){
/*---RUAISI---*/
FIX
}
FIX

Because read is in fact still splitting things on IFS (and then putting them back together), you end up losing leading or trailing whitespace. You can fix this by making IFS include only end-of-line by adding the following to the top of the script:

IFS='\n'

I would still suggest that bash isn't necessarily the right tool for this job. Either sed or awk is probably going to be more effective. Here's the same thing as an awk script:

#!/usr/bin/awk

/sendMessage4K/ || /alpha_display\(/ {
    print "/*---RUAISI---*/"
    print
    next
}

{print}

If you saved this in a file named "fixit.awk", you would run it like this:

awk -f fixit.awk < temp1 > temp2

Upvotes: 1

choroba
choroba

Reputation: 241898

You are using the regular expression matching operator =~, but on the right hand side of it, there is no regular expression, but a shell wildcard expression. So, change it to

[[ $LINE == *hello_dude\(* ]]

or

[[ $LINE =~ hello_dude\( ]]

i.e. use either wildcard with the proper operator, or a regex with the proper operator.

Update: Looking at the updated script, I see the problem: you are using for where you should be using while:

#! /bin/bash

while read LINE ; do
  if [[ $LINE = sendMessage4K* ]]; then
     echo '/*---RUAISI---*/' >> temp2
     echo "$LINE" >> temp2
   elif [[ $LINE =~ *alpha_display\(* ]]; then
     echo "$LINE" >> temp2
     echo '/*---RUAISI---*/' >> temp2
  else
     echo "$LINE" >> temp2
  fi
done < temp1

To avoid deletion of leading whitespace, add this line before the while:

IFS=$'\n'

Upvotes: 1

larsks
larsks

Reputation: 311635

Without seeing your script we can't really help you with that. However, this sort of problem -- inserting a line of text before a particular matching pattern -- is often handled using sed. For example, if I have a file that looks like this:

one
two
three

And I want to insert "Bananas" before "two", I would do something like this:

sed '/two/ i\Bananas'

Which gives me:

one
Bananas
two
three

This assumes GNU sed (although it would work with minor modifications for other versions of sed, also).

Upvotes: 0

Related Questions