[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: smart indented HERE docs

From: Paul Donohue
Subject: Re: smart indented HERE docs
Date: Mon, 22 Aug 2016 17:14:21 -0400

I agree something like this would be nice.  Especially if it could handle 
spaces (in addition to tabs).

My current solution to this problem is not particularly pretty or elegant:
alias CAT_TO_END="I=\"\${I/*\$'\n'/}\" ; alias START=\"perl -ple 's/^\$I//' 
<<'\${I}END' ; unalias START\""$'\n'START
shopt -s expand_aliases
if true ; then  # Not relevant, except to illustrate a section of the script 
that should be indented
  def python_function():
    print("Hello World!")

To explain:
I put the prefix I want to strip off of each line into $I.  In the above 
example, the value assigned to $I is split across two lines so that $I contains 
an actual indent from a line of the shell script (the indent of the CAT_TO_END 
line), which eliminates the need to manually update the value assigned to $I if 
I later change the way the shell script is indented.  It's too bad that 
$BASH_COMMAND doesn't include any leading whitespace, as that would be a better 
way to get the actual indent from a line of the shell script.
I then run the CAT_TO_END alias.  This alias first removes any characters up to 
and including a newline from the value in $I, to handle the case were the 
assignment to $I is split across two lines as shown above.  ($I should only 
contain the relevant prefix, so I strip off the \n and anything before the \n 
and only keep the indent from the following line.)  CAT_TO_END then defines 
another alias (START) and runs it.
The definition and use of the second alias (START) is a hack to allow me to use 
the value of $I as part of the here document's delimiter.  This allows the END 
delimiter to be indented using an arbitrary prefix without requiring me to 
hard-code the indent using <<'  END'.
The START alias then pipes the here document into perl, which then strips the 
value of $I off each line before printing it to STDOUT.  After perl exits, the 
START alias unaliases itself.

A nice feature of the above is its ability to strip any arbitrary prefix, 
including any combination of spaces and tabs.  I generally prefer to indent my 
scripts using 2 spaces rather than 1 tab, so <<- doesn't really work for me in 

Unfortunately, the above will not work if you try to put it in a function, due 
to the way bash parses function definitions.  However, if you can live without 
the convoluted magic that allows the script to dynamically detect its own 
indent, you can simplify the above to the following, which will work in a 
        perl -ple 's/^  //' <<' END'
        def python_function():
                print("Hello World!")

In any case, something like <<+END would be much cleaner.

On Sun, Aug 21, 2016 at 11:47:40PM -0400, Derek Schrock wrote:
> I believe this would be a feature request however if this already
> exists directly in bash please let me know.
> With <<- you can indent a here-doc such that all tabs will be removed.
> This can be nice for style reasons in your script however to give the
> impression of formatting in the here-doc spaces can be added:
>       ....
>       cat <<- EOF
>       Testing 1 2 3
>       Testing 4 5 6
>        Testing 7 8 9
>       EOF
>       ...
> Keep in mind the above is prefixed with tabs so with <<- all the prefixed
> tabs are removed.
> Would result with:
> Testing 1 2 3
> Testing 4 5 7
>  Testing 7 8 9
> Would it be possible to add a new character (+) to the here-doc such
> that the number of tabs remove are the number after the closing
> delimiter (EOF in the above example):
>       ....
>       cat <<+ EOF
>               Testing 0 9 8
>               Testing 7 6 5
>               Testing 4 3 2
>       EOF
> Note the above here-doc is tabbed out by two but the closing delimiter
> is only tabbed by 1 so only 1 tab is removed.
> Would result with:
>       Testing 0 9 8
>       Testing 7 6 5
>       Testing 4 3 2
> This would allow you to write here-docs inside functions and continue to
> use tabs to maintain proper formatting and not have to use spaces.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]