0

I am trying to search for a particular line in a file using grep command and I am successful doing that.

Now I want to copy the entire line to a new line right after the original line. In other words, the original line should be followed by the new line with same content with some prefix.

For example: Original data :

Apple 
Samsung
Nokia
HTC

Say if I want the new data to look like

Apple
Samsung
prefix Samsung
Nokia
HTC

Note: I have multiple patterns with Samsung, where ever I found that it should do the same.

I tried to grep and pipe with sed and I failed. Can anyone please help me with this?

Thanks

3
  • grep means g/re/p, it's for finding strings that match a regexp and printing them, not for modifying anything, sed is best kept to just doing s/old/new on individual lines as after that it gets complicated and/or non-portable, and any time you need sed | grep or vice-versa you should be using awk instead for clarity, efficiency, portability, robustness, etc.
    – Ed Morton
    Apr 6 '21 at 15:39
  • 3
    You should have included regexp metachars and potential partial match failures in your example. See how-do-i-find-the-text-that-matches-a-pattern. With the posted example you'll get answers that work for that example but not other values you're likely to encounter in your real data.
    – Ed Morton
    Apr 6 '21 at 15:44
  • 2
    Actually - I assumed given your subject line How to copy an entire line which matches the string... that you wanted to do a full-line string match but now I see in your comment you say I have multiple patterns with Samsung... so now I'm not so sure. Please fix your question to clearly state if you want to do a regexp or string match, and if you want to do full-line, full-word, or partial matching and make sure your sample input/output covers the cases where a false match is likely, not just one trivial sunny day case
    – Ed Morton
    Apr 6 '21 at 16:10
4

You could do this using awk.

Using your example here is one way to do it.

awk '{print $0} /Samsung/ {print "prefix " $0}' filename

Breaking down the statement for you: {print $0} is to print the entire line

/Samsung/ {print "prefix " $0} says to print "prefix " followed by the entire line, but only if the line contains Samsung.

5
  • 1
    This would insert the prefix on each line containing the substring Samsung, for example on a line saying Not Samsung.
    – Kusalananda
    Apr 6 '21 at 15:38
  • It would print all lines and then also print another line with prefix Samsung directly following any line containing Samsung. I tested it and the output is exactly as the example requested.
    – Natolio
    Apr 6 '21 at 15:40
  • 1
    The point is it'll print a line that contains Samsung, not just a line that is Samsung. It'll also fail if the line in question contains regexp metachars. You need to do $0 == "Samsung" (i.e. a full line string match) , not /Samsung/ (i.e. a partial line regexp match). Getting the expected output from some sample input is the starting point to a solution, not the end point.
    – Ed Morton
    Apr 6 '21 at 15:40
  • The question explicitly states that they have multiple patterns with Samsung and that wherever found they would like to do the same though. Saying $0 == "Samsung" would not follow that behavior. I see no issue with a partial line regexp match because of this. I do see your point about the regexp metachars though.
    – Natolio
    Apr 6 '21 at 15:44
  • No problem, I just posted my own answer.
    – Ed Morton
    Apr 6 '21 at 15:47
3
sed -n 'p;s/^Samsung$/prefix &/p' file >newfile

This first outputs the current line. It then substitutes the string Samsung with prefix, a space, and the matched string (which is what & will expand to in the replacement string), effectively inserting the string prefix in front of Samsung on each line that is Samsung only. If the substitution succeeds, the modified line is printed, creating an additional new line in the output.

The output is then written to a new file, newfile.

If you want to relax the matching of the string Samsung so that it matches anywhere on the line, then use, for example,

sed -n 'p;s/.*Samsung/prefix &/p' file >newfile

Using awk to implement the equivalent of the above:

awk '1; /^Samsung$/ { print "prefix", $0 }' file >newfile

The lone 1 is a short-cut way of writing { print }, which in turn is the same as { print $0 }, which outputs the current line.

Use just /Samsung/ to match the string Samsung anywhere on the line rather than requiring that the line is just that string.

Obfuscated variant of the awk command above:

awk '1; /^Samsung$/ && $0 = "prefix " $0' file >newfile
2

This is a solution using GNU sed. It finds the string "Samsung" and replaces with itself and adds a new line with the matched pattern "Samsung", adding at the beginning of it "prefix ":

# doubled the example data to show it works on every line
$ sed 's/^Samsung$/&\nprefix &/' file
Apple 
Samsung
prefix Samsung
Nokia
HTC
Apple 
Samsung
prefix Samsung
Nokia
HTC
0
1
$ awk '{print} $0=="Samsung"{print "prefix", $0}' file
Apple
Samsung
prefix Samsung
Nokia
HTC

With a more comprehensive test case, imagine trying to duplicate the line test.* in this input file:

$ cat file
Apple
the testing regexp match failure case
Samsung
the test.* partial string match failure case
Nokia
test.*
HTC

So in the output only that 2nd-last line of test.* should be duplicated. My script does a full-line string match and so there's no problem, it only duplicates the one line that is exactly the string test.*:

$ awk '{print} $0=="test.*"{print "prefix", $0}' file
Apple
the testing regexp match failure case
Samsung
the test.* partial string match failure case
Nokia
test.*
prefix test.*
HTC

Try that same case with the other solutions you have.

If you do want to do a partial string match then you may want:

awk '{print} index($0,"Samsung"){print "prefix", $0}' file

but that would match "Samsungtheblues" which may or may not be what you want so I'll wait for you to clarify your requirements and provide a better example before making any further suggestions.

1

Another sed implementation, using the "hold space"

sed '/Samsung/ {h; s/^/prefix /; H; g;}' file

Ref: https://www.gnu.org/software/sed/manual/html_node/Other-Commands.html

0

Using POSIXly sed we can double the line by storing in hold but appending to pattern space only for Samsung lines. Then we place a prefix right after the newline separating the duplicated (Samsung) lines. For the others, the newline wouldn't show up so the substitution won't happen and sed will print the pattern space unchanged.

sed -e '
  h;/Samsung/G
  s/\n/&prefix /
' file

Another way is to first print the pattern space for all lines. And then , only for Samsung lines, prefix and print them.

sed -ne '
  p
  /Samsung/s/^/prefix /p
' file

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.