0

I'm trying to put together a bash script that will search a bunch of files and if it finds a particular string in a file, it will add a new line on the line after that string and then move on to the next file.

#! /bin/bash
echo "Creating variables"
SEARCHDIR=testfile
LINENUM=1
find $SEARCHDIR* -type f -name *.xml | while read i; do
echo "Checking $i"

  ISBE=`cat $i | grep STRING_TO_SEARCH_FOR`
   if [[ $ISBE =~ "STRING_TO_SEARCH_FOR" ]] ; then
     echo "found $i"
     cat $i | while read LINE; do
      ((LINENUM=LINENUM+1))
      if [[ $LINE == "<STRING_TO_SEARCH_FOR>" ]] ; then
        echo "editing $i"
        awk -v "n=$LINENUM" -v "s=new line to insert" '(NR==n) { print s } 1' $i 
      fi
  done
  fi
LINENUM=1
done

the bit I'm having trouble with is

awk -v "n=$LINENUM" -v "s=new line to insert" '(NR==n) { print s } 1' $i 

if I just use $i at the end, it will output the content to the screen, if I use $i > $i then it will just erase the file and if I use $i >> $i it will get stuck in a loop until the disk fills up.

any suggestions?

1
  • 1
    Then just redirect to a temp file and then move it to your original one. Also, I guess your code could be reduced a lot using the right tools. A find and awk should be more or less enough, whereas you use many different things. Commented Dec 30, 2014 at 14:44

3 Answers 3

1

Unfortunately awk dosen't have an in-place replacement option, similar to sed's -i, so you can create a temp file and then remove it:

awk '{commands}' file > tmpfile && mv tmpfile file

or if you have GNU awk 4.1.0 or newer, the -i inplace is added, so you can do:

awk -i inplace '{commands}' file

to modify the original

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

Comments

1
#cat $i | while read LINE; do
#  ((LINENUM=LINENUM+1))
#  if [[ $LINE == "<STRING_TO_SEARCH_FOR>" ]] ; then
#    echo "editing $i"
#    awk -v "n=$LINENUM" -v "s=new line to insert" '(NR==n) { print s } 1' $i 
#  fi
# done

# replaced by
sed -i 's/STRING_TO_SEARCH_FOR/&\n/g' ${i}

or use awk in place of sed

also

# ISBE=`cat $i | grep STRING_TO_SEARCH_FOR`
# if [[ $ISBE =~ "STRING_TO_SEARCH_FOR" ]] ; then
#by
if [ $( grep -c 'STRING_TO_SEARCH_FOR' ${i} ) -gt 0 ]; then
# if file are huge, if not directly used sed on it, it will be faster (but no echo about finding the file)

Comments

1

If you can, maybe use a temporary file?

~$ awk ... $i > tmpfile
~$ mv tmpfile $i

Or simply awk ... $i > tmpfile && mv tmpfile $i

Note that, you can use mktemp to create this temporary file.

Otherwise, with sed you can insert a line right after a match:

~$ cat f
auie
nrst
abcd
efgh
1234

~$ sed '/abcd/{a\
new_line
}' f
auie
nrst
abcd
new_line
efgh
1234

The command search if the line matches /abcd/, if so, it will append (a\) the line new_line.

And since sed as the -i to replace inline, you can do:

if [[ $ISBE =~ "STRING_TO_SEARCH_FOR" ]] ; then
     echo "found $i"
     echo "editing $i"
     sed -i "/STRING_TO_SEARCH_FOR/{a
\new line to insert
}" $i 
fi

2 Comments

it is best to use awk '...' file > tmp && mv tmp file, like user00...0001 did. The && trick prevents overwriting file with some bad output in case awk failed.
Thanks, I went with the sed option. I found I also had a problem with my loop but the sed method allowed me to uncover it.

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.