Premise: I am modifying my .profile, and wanted to add a large ASCII text for "profile" generated by figlet as comment to the beginning of the file.

I could do it in multiple steps, but I was trying to find a way to do it in the shortest steps possible.

figlet generates the large ascii text, and I append # to the beginning of every line using sed:

figlet -f slant "p r o f i l e" | sed -n 's/^.*/#&/p'

The output to the above:

#                               ____   _    __      
#    ____     _____   ____     / __/  (_)  / /  ___ 
#   / __ \   / ___/  / __ \   / /_   / /  / /  / _ \
#  / /_/ /  / /     / /_/ /  / __/  / /  / /  /  __/
# / .___/  /_/      \____/  /_/    /_/  /_/   \___/ 

Now, I want to append this to the beginning of .profile. I have tried till now, with: sed, xargs But, I have not yet achieved the desired results, i.e, doing the entire process in a single line of commands.

I could definitely break it down into 2 lines and solve it, but isn't there any solution to achieve this in a single line?

  • can u share the desire result...
    – Siva
    Feb 19 '20 at 6:22
  • Desired result: The large ascii text (as comments) is appended to the beginning of .profile followed by the pre-existing contents of the same.
    – RG7
    Feb 19 '20 at 6:49

One way using ed(1) which should work on both GNU and BSD variants.

printf '%s\n' '0a' "$(figlet -f slant "p r o f i l e" | sed -n 's/^.*/#&/p')" "" . w | ed -s ~/.profile
  • printf '%s\n' Is just like echo but more versatile.
  • "$( )" is called command substitution which captures the output of a command. Note that it is enclosed by double quotes for a reason.
  • 0 is the address or the line number in the buffer/file, which is the first line, although 1i should work too but I prefer 0a since 1i will fail on empty files
  • a is the command which means add or append, .
  • "" is just to create an empty/new line after the output of figlet
  • . Tells ed that we are done editing.
  • w means write.
  • Then piping | to ed
  • With the -s flag which means silent.
  • Thanks, for your help and the clear explanation. That worked flawlessly. I have not used ed before, but seeing the solution, it looks interesting.
    – RG7
    Feb 19 '20 at 7:01
  • 1
    Good to know that it works for you. Ed is not so popular these days, some even say that it is just a fringe of the ancient unix times. Sed is popular now because some variants has the -i option which edit the file in-place as well.
    – Jetchisel
    Feb 19 '20 at 9:21

An alternative using ex(1), the vi/vim equivalent to ed:

ex ~/.profile <<EOF
0r !figlet -f slant "p r o f i l e" | sed 's/^/\#/'

Inserts the results of the figlet pipeline before the first line of the file, and saves it.

  • The answer is a very easy to follow, and although it has multiple steps, it is simple enough to understand.
    – RG7
    Feb 19 '20 at 14:35

One can go with GNU sed all the way:

sed -i '1{H;s/.*/figlet -f slant "p r o f i l e"/e;s/^/#/mg;G}' ~/.profile

Note the e modifier to that first s command, which executes the pattern space, the figlet command I create.

  • Can you please elaborate on the workings a little? I have understood the command, but I am still confused as to why H is in the beginning and G is at the end. Initially, the pattern space is empty, so with H, it will copy an empty pattern space to the hold space? At the end, does the hold space contain the modified pattern, which is then copied back to the pattern space? That pattern space is then inserted to the 1st line of the `.profile' file?
    – RG7
    Feb 19 '20 at 14:09
  • Thanks, for the answer. It is the shortest solution, despite it being a little difficult to understand. I have finally understood what this command is doing, and the precise position and usage of H and G at their relative position. Yet, could you please elaborate a little more in your answer for others.
    – RG7
    Feb 19 '20 at 14:25
  • 1
    @RG7 I'm coming from work at very late hours, so if you don't mind, I'll provide an explanation in the weekend. Thank you very much for your comments. Sed indeed can be hard to read, but fyi I struggled with the other answers.
    – seshoumara
    Feb 19 '20 at 22:11

Since you are using sed already, you can do it in a couple of simple calls to sed:

figlet -f slant "p r o f i l e" | sed 's/^./#&/' | sed '' - file

The last sed call concatenates stdin (-) and the file (without change).

Of course, one call to awk could do it:

figlet -f slant "p r o f i l e" | awk 'NR==FNR{gsub(/^/,"#")}1' - file

Or, if you like ed, you could do:

echo 'r !figlet -f slant "p r o f i l e"
r file
Q' | ed -s

Hmmm, you wanted a one-liner:

printf '%s\n' 'r !figlet -f slant "p r o f i l e"' ,s/^/#/ 'r file' w Q| ed -s

That means:

printf '%s\n'                           # print each argument on one line.
'r !figlet -f slant "p r o f i l e"'    # read the output of a sh command.
,s/^/#/                                 # insert a # at each line start.
'r file'                                # read the file
w                                       # write (the file)
Q                                       # Quit
|                                       # pipe the commands to the ed call
ed -s                                   # call ed in silent mode.

Try (untested)

figlet -f slant "p r o f i l e" | sed -n 's/^.*/#&/p' | cat - .profile
  • It works, but o/p to stdout, rather than .profile and, cannot be piped to the same file, if that is used in conjunction.
    – RG7
    Feb 19 '20 at 12:26

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.