3

I know about r command in sed and that it can be used in combination with regular search pattern or with regexp. However I found out that regexp in sed works differently than in grep and I just want to use grep to get the line number after which to insert text. But I am failing to find how in sed I can specify a line number after which to insert a text of a external file ( command r ). Any ideas?

As related to expected output.

Input file 1 a.tmp:

Line1
Line2
Line3

Input file 2 b.tmp:

SubLine1
SubLine2
SubLine3

Suppose I want to insert b.tmp into a.tmp after line #2. I would expect to see this:

Line1
Line2
SubLine1
SubLine2
SubLine3
Line3

How would I do it?

reardenlife
  • 317
  • 4
  • 15
  • FYI, the [tag:r] tag is about the R programming language, not something within `sed`. (I don't know about the `r` command anyway ... can't find it in the man page, can you provide a reference for it?) – r2evans Aug 10 '19 at 15:02
  • It would help if you provide a MWE for this, including your expected output. – r2evans Aug 10 '19 at 15:03
  • 1
    @r2evans I posted the expected output. – reardenlife Aug 10 '19 at 15:09
  • 1
    does this work for you? `sed '2r b.tmp' a.tmp` – Sundeep Aug 10 '19 at 15:10
  • Learned about the "r" command ... not sure why I can't find it in the man-page. Thanks. (Now I see it ... should have looked another minute before that first comment :-) – r2evans Aug 10 '19 at 15:11
  • 1
    `regexp in sed works differently than in grep` can you give an example? both of them support BRE/ERE – Sundeep Aug 10 '19 at 15:12
  • @Sundeep yeah! This is exactly what I was looking for. But where such a syntax is described? – reardenlife Aug 10 '19 at 15:24
  • @reardenlife sorry for interrupting your chat, but i suggest you [this](http://www.grymoire.com/Unix/Regular.html#uh-6) article :) – nonForgivingJesus Aug 10 '19 at 15:27
  • @Sundeep as related to regexp usage in sed. For example I have this code: ```bash n=$(cat a.tmp | grep -Fn "$pattern" | cut -f1 -d:) sed -i "${n}r insert.tmp" a.tmp ``` How would you suggest I modify it to get rid of grep, via sed alone provided there might be all kinds of special symbols in $pattern? – reardenlife Aug 10 '19 at 15:39
  • 1
    @reardenlife for GNU sed, I'd recommend the [online manual](https://www.gnu.org/software/sed/manual/sed.html#sed-addresses).. I have [some examples too on github](https://github.com/learnbyexample/Command-line-text-processing/blob/master/gnu_sed.md#line-filtering-options).. `-F` is sorely missing in `sed`, you'll need something like https://stackoverflow.com/questions/29613304/is-it-possible-to-escape-regex-metacharacters-reliably-with-sed ... I'd rather go for awk/perl in this case – Sundeep Aug 10 '19 at 15:42

2 Answers2

3

Just use awk. Looks how simple and consistent (and also portable to all awks in all shells in every UNIX box and is efficient) it is to do whatever you want:

Insert a file after a line number:

$ awk 'NR==FNR{n=n s $0; s=ORS; next} {print} FNR==2{print n}' b.tmp a.tmp
Line1
Line2
SubLine1
SubLine2
SubLine3
Line3

Insert a file after a line containing a string matching a regexp:

$ awk 'NR==FNR{n=n s $0; s=ORS; next} {print} /Line2/{print n}' b.tmp a.tmp
Line1
Line2
SubLine1
SubLine2
SubLine3
Line3

Insert a file after a line that is a string (full line string match):

$ awk 'NR==FNR{n=n s $0; s=ORS; next} {print} $0=="Line2"{print n}' b.tmp a.tmp
Line1
Line2
SubLine1
SubLine2
SubLine3
Line3

Insert a file after a line containing a string (partial line substring match):

$ awk 'NR==FNR{n=n s $0; s=ORS; next} {print} index($0,"Line2"){print n}' b.tmp a.tmp
Line1
Line2
SubLine1
SubLine2
SubLine3
Line3

Insert a file before a line number:

$ awk 'NR==FNR{n=n s $0; s=ORS; next} FNR==2{print n} {print}' b.tmp a.tmp
Line1
SubLine1
SubLine2
SubLine3
Line2
Line3

Insert a file instead of a line number:

$ awk 'NR==FNR{n=n s $0; s=ORS; next} FNR==2{print n; next} {print}' b.tmp a.tmp
Line1
SubLine1
SubLine2
SubLine3
Line3

etc., etc. - any kind of matching you want to do and any action you want to take when that match succeeds is trivial, consistent, clear, portable, efficient and easy to modify/expand if/when your requirements change.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
2

I will citate this page (actually really good tutorial about sed in all terms):

There is also a command for reading files. The command sed '$r end' <in>out will append the file "end" at the end of the file (address $)." The following will insert a file after the line with the word "INCLUDE"

sed '/INCLUDE/ r file' <in >out You can use the curly braces to delete the line having the "INCLUDE" command on it:

sed '/INCLUDE/ {
    r file
    d
}'

The order of the delete command d and the read file command r is important. Change the order and it will not work. There are two subtle actions that prevent this from working. The first is the r command writes the file to the output stream. The file is not inserted into the pattern space, and therefore cannot be modified by any command. Therefore the delete command does not affect the data read from the file.

The other subtlety is the d command deletes the current data in the pattern space. Once all of the data is deleted, it does make sense that no other action will be attempted.

  • Yeah, I seen it. But it is not about line number. It is about search pattern.. Am I missing something? – reardenlife Aug 10 '19 at 15:12
  • 1
    @reardenlife you can pass number of the line/regular expression as address or range. For example `sed -n '2p'` will print only second line, and `sed -n '/2/p'` will print every line, where sed encountered 2. **TL;DR**: everywhere you can use `/smth/`, you can use number – nonForgivingJesus Aug 10 '19 at 15:14