0

I did search and found how to replace each occurrence of a string in files. Besides that I want to add one line to a file only at the first occurrence of the string.

I know this

   grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

will replace each occurrence of string. So how do I add a line to that file at first match of the string? Can any have an idea how to do that? Appreciate your time.

Edited :

Exaple : replace xxx with TTT in file, add a line at starting of file for first match.

Input : file1, file2.

file1
  abc xxx pp
  xxxy rrr 
  aaaaaaaaaaaddddd


file2 
  aaaaaaaaaaaddddd   

Output

file1
  #ADD LINE HERE FOR FIRST MATCH DONT ADD FOR REST OF MATCHES
  abc TTT pp
  TTTy rrr 
  aaaaaaaaaaaddddd

file2
  aaaaaaaaaaaddddd
guru th
  • 149
  • 1
  • 1
  • 14
  • Do you want to add a blank line ? –  Oct 14 '14 at 12:34
  • 1
    see http://stackoverflow.com/a/9453461/3297613 – Avinash Raj Oct 14 '14 at 12:40
  • Post some sample input and expected output. FYI neither sed nor grep work on strings, they work on REs. The difference is a loaded gun pointed at your foot. Also, the UNIX tool to find files is named `find`. The `-r` option that the GNU guys added to grep is a terrible idea that goes against the UNIX philosophy and all good programming advice. – Ed Morton Oct 14 '14 at 15:11

2 Answers2

2

Cribbing from the answers to this question.

Something like this would seem to work:

sed -e '0,/windows/{s/windows/linux/; p; T e; a \new line
;:e;d}; s/windows/linux/g'

From start of the file to the first match of /windows/ do:

  • replace windows with linux
  • print the line
  • if s/windows/linux/ did not replace anything jump to label e
  • add the line new line
  • create label e
  • delete the current pattern space, read the next line and start processing again

Alternatively:

awk '{s=$0; gsub(/windows/, "linux")} 7; (s ~ /windows/) && !w {w=1; print "new line"}' file
  • save the line in s
  • replace windows with linux
  • print the line (7 is true and any true pattern runs the default action of {print})
  • if the original line contained windows and w is false (variables are empty strings by default and empty strings are false-y in awk)
    • set w to 1 (truth-y value)
    • add the new line
Community
  • 1
  • 1
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
1

If I understand you correctly, all you need is:

find . -type f -print |
while IFS= read -r file; do
    awk 'gsub(/windows/,"unix"){if (!f) $0 = $0 ORS "an added line"; f=1} 1' "$file" > tmp &&
    mv tmp "$file"
done

Note that the above, like sed and grep would, is working with REs, not strings. To use strings would require the use of index() and substr() in awk, is not possible with sed, and with grep requires an extra flag.

To add a leading line to the file if a change is made using gNU awk for multi-char RS (and we may as well do sed-like inplace editing since we're using gawk):

find . -type f -print |
while IFS= read -r file; do
    gawk -i inplace -v RS='^$' -v ORS= 'gsub(/windows/,"unix"){print "an added line"} 1' "$file"
done
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • your script is adding text at a place where the 1st match is found, i want to add text at 1st line of file whenever the 1st match is found... thank #Morton – guru th Oct 15 '14 at 07:25
  • Can you suggest a modification for my requirement ? – guru th Oct 15 '14 at 07:26