7

I have the line number 55 in a text file which I want to move just before line number 23 in the same text file. I know that you can move lines up by a certain number of lines 1, 2 but is it possible to append or prepend a line to another line instead of the verbose way of moving lines up or down a textfile?

I am open to answers using vim, sed or any other command line tool but the more concise the better

update:

The sed command i inserts text before a line which is similar to what I am looking for except that I want to insert a line before a line

bit
  • 1,106

3 Answers3

12

A scriptable editor makes this pretty straight-forward!

printf '%s\n' '55m22' 'wq' | ed -s input

This sends two commands to ed (editing the file named input):

  1. 55m22 -- move line 55 after line 22
  2. wq -- save the file back to disk and quit.
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
  • It worked almost perfectly but I didn't read your answer fully so it moved line 55 after line 22, which is not a big deal just something to keep in mind. As for the command you posted: Why did you separate the two commands with a line break, usually when piping from one command to another the second command connected to the end of the pipe receives the output from the pipe as a series of arguments e.g. in a directory that contains directory1 and directory2 echo * | ls -l is equivalent tols -l directory1 directory2. Why not printf '%s ' '55m22' 'wq' | ed -s input'? – bit Jul 21 '19 at 19:39
  • @MyWrathAcademia that's not how pipes work and also not how ls works. The word splitting is usually done by the shell alone, but the shell does not modify what goes into the pipe. Pipes transfer raw data, it's up to the target program what to do with it. If ed expects one command per line, that is what you have to provide. – frostschutz Jul 21 '19 at 19:47
  • I used 22 because the move command moves the addressed line after the target line and you wanted it to land before line 23. – Jeff Schaller Jul 21 '19 at 19:57
  • @frostschutz , thanks for the correction, can you specify which part of my description of a pipe was misinformed? Is it the bit about a series of arguments or the command after the pipe being connected to the end of the pipe? As for the "word splitting being done by the shell alone", isn't the command line user the one that specifies the word splitting to the shell in the form of \n (line feed), (white space), \r (carriage return) etc.? – bit Jul 21 '19 at 19:57
  • 1
    The line break you see in the printf format sends the commands with a newline so that ed sees them as two separate commands, just as if you had run ed interactively. – Jeff Schaller Jul 21 '19 at 19:58
  • @MyWrathAcademia, echo * | ls doesn't make sense because ls doesn't read stdin, it's not equivalent to ls -l *. Word splitting means the splitting that happens to unquoted expansions, it doesn't seem to apply here. – ilkkachu Jul 22 '19 at 06:54
  • I like to see good old ed still used (it is very usefull on large files, for exemple). good answer. – Olivier Dulac Jul 22 '19 at 18:34
4

A little shorter:

ex input <<<"55m22|wq"
steve
  • 21,892
  • If you are assuming this level of shell support, one could also write ed -s input <<< $'55m22\nwq'. The main benefit to using ex would be the ability to use a single pipe-delimited command rather than a series of newline-terminated commands. Otherwise, you would write printf '55m22|wq\n' | ex input, which saves three characters over printf '55m22\nwq\n' | ed -s input. – chepner Jul 22 '19 at 17:13
3

It's somewhat longer in vi than in ed:

vi input
55Gdd23GPZZ

55G ... go to line 55
dd ... delete one line
23G ... go to line 23
P ... paste the deleted line before line 23
ZZ ... write file and exit

Jim L.
  • 7,997
  • 1
  • 13
  • 27