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,076
  • 2
  • 17
  • 36

3 Answers3

11

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
  • 66,199
  • 35
  • 114
  • 250
  • 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 to`ls -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 `m`ove 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 *`](https://unix.stackexchange.com/questions/531285/redirection-operator-standard-input-and-command-parameters). Word splitting means the [splitting that happens to unquoted expansions](https://unix.stackexchange.com/questions/68694/when-is-double-quoting-necessary), 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
  • Obligatory [ed, man! !man ed](https://www.gnu.org/fun/jokes/ed-msg.html) – Josh Jul 23 '19 at 04:23
4

A little shorter:

ex input <<<"55m22|wq"
steve
  • 21,582
  • 5
  • 48
  • 75
  • 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,188
  • 1
  • 13
  • 25