2

I am trying to have a sed script that makes changes and outputs a new file, but it must add two comment lines to the top, so that the output file can then be itself run as a bash script. The trouble is that all the solutions I have seen for adding two top lines do not apply to comments, which render the script itself non-functioning.

So for example if my sed results in a file like this:

AAAA
BBBB
CCCC
DDDD

I want to end up with something looking like this:

#$ -cwd
#$ -pe mpi 16

AAAA BBBB CCCC DDDD

I have already tried variations on things like this:

sed -i '1s/^/#$ -cwd\n/' output.txt

But these will treat everything past the # as comment.

How can I write a bash script that will add the comment headers without messing itself up? Thanks!

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255

2 Answers2

2

Kusalananda's answer is probably the best solution as it will always work, but I have also verified that using a sed only solution works too:

$ cat output.txt 
AAAA
BBBB
CCCC
DDDD
$ sed '1i#$ -cwd\n#$ -pe mpi 16\n' output.txt 
#$ -cwd
#$ -pe mpi 16

AAAA BBBB CCCC DDDD

Basically using sed's (i)nsert command instead of (s)ubstitute:
1 - operate on line 1
i - insert before
1i - insert before line 1

This works using gnu sed 4.8. YMMV

Dani_l
  • 4,943
1

To avoid all problems with having to quote special characters etc. for use with sed, use a quoted here-document:

cat - output.txt <<'END_COMMENTS' >newfile.txt
#$ -cwd
#$ -pe mpi 16

END_COMMENTS

This concatenates your three lines of extra text with the contents of your existing file output.txt, and places the resulting text in newfile.txt. You are then free to rename newfile.txt into output.txt if you want.

The cat command is used with two arguments here:

  1. -; this instructs cat to first read from standard input. The standard input stream will contain the here-document containing your header text.
  2. output.txt; this is your existing file. It will be read whenever the data arriving on standard input is all read.

Testing:

$ cat output.txt
AAAA
BBBB
CCCC
DDDD

The > prompt at the start of the lines below is the secondary prompt of the bash shell, used when more input is needed to complete a command.

$ cat - output.txt <<'END_COMMENTS' >newfile.txt
> #$ -cwd
> #$ -pe mpi 16
>
> END_COMMENTS
$ cat newfile.txt
#$ -cwd
#$ -pe mpi 16

AAAA BBBB CCCC DDDD

Note that if the final output is supposed to be a bash shell script, then the first line of your header should be a #!-line with the absolute pathname of the bash interpreter.


You could also just use printf:

printf '%s\n' '#$ -cwd' '#$ -pe mpi 16' '' |
cat - output.txt >newfile.txt

Instead of a here-document, this uses printf to generate the three lines of header text. The result will be the same, but it looks uglier and you need to understand the code to see what the header text actually looks like (unless you run it, obviously).

Kusalananda
  • 333,661