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: #!/bin/bash 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 I=' ' CAT_TO_END def python_function(): print("Hello World!") END fi 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 general. 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 function: #!/bin/bash print_python_code() { perl -ple 's/^ //' <<' END' def python_function(): print("Hello World!") END } print_python_code 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. >