8

I am wondering whether there is a simple way to operate on certain lines with preassigned line numbers.

Let's say I want to output the 1st, 7th, 14th and 16th lines of a file, I can simply do

sed -n '1p;7p;14p;16p' input_file

but this gets more complicated when the operation is not just printing, and I don't want to write the same long command 4 times (and yes, I know I can construct this long sed command by substituting the same bash variable 4 times, but that's not ideal enough ...) , i.e.

sed -n '1{long_command};7{long_command};14{long_command};16{long_command}' input_file

Is there a way to do the operation on these specific lines of my file? I am expecting something like,

sed -n '1,7,14,16p'

which certainly will not work in the current form.

Any help will be appreciated. "No, it is not possible." with explanations is also an answer that I will accept.

11

You can use branches:

sed '
  1b1
  7b1
  14b1
  16b1

  # for the rest to be left alone, branch off (or delete them with "d"):
  b

  :1
  long_command'

(note that you can also add some 20,25b1 line ranges, or /re/b1 to include lines that match the re).

Or you could use awk:

awk 'NR == 1 || NR == 7 || ... {stuff}'

Or using a hash:

awk -v l=1,7,14,16 '
  BEGIN{split(l, a, ","); for (i in a) lines[a[i]]}

  NR in lines {stuff}'

(or BEGIN{lines[1]lines[7]lines[14]lines[16]} if there aren't too many)

  • Thank you, never thought of branches ... It just seem to be the ideal tool to use in this case. – Weijun Zhou Jan 15 '18 at 16:44
  • how do use branches like this in sed with a search pattern? like say I wanna match or delete a pattern after the nth line? – qodeninja Jul 28 '18 at 20:47
3

Simply invert your selection and delete it:

sed '2,6d;8,13d;15d;17,$d;long_command'
  • This is also a nice solution although a little harder for handling line numbers that are read from stdin, for example. – Weijun Zhou Jan 15 '18 at 17:08
1

First variant:

You can use this trick:

sed -nf <(printf '%dp\n' 1 7 14 16)

-f script-file - add the contents of script-file to the commands to be executed.

Testing

seq 1 20 | sed -nf <(printf '%dp\n' 1 7 14 16)

Output

1
7
14
16

Second variant:

In the beginning, the auxiliary sed is used for filtering only needed lines from the file, then these lines piped to the main sed with the long command.

sed -n '1p; 7p; 14p; 16p' input.txt | sed 'long command'

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.