I am trying to "beautify" scripts automatically by using declare -f function
In a nutshell: Given a bash script foo
, you can apparently "automagically" indent it by doing, in bash:
MAGIC () { ...here you copy/paste the whole foo script... ; } ; declare -f MAGIC
I provide an example script below that does that for any script you give it as input.
My question is : what are the main caveats of using an encompassing function and then declare -f
it ?
- any special dangers?
- limit on the number of function nesting ? (I can have functions in the script, they are happily indented as well, but how many levels deep can I go?)
- "won't be able to do this/interpret that/…" ? (it seems awk script get fine, and are even indented a bit (the main script is aligned to the rest of the script) … but what (other) things could pose problems?
- will lose some informations? I noticed: it removes blank lines, and comments (
# ...
), but what else does it discard/modify?
I want to get your input before I can use my "indent" script below to reindent a bunch of bash scripts…
Here is my first attempt, comments (and answers about concerns above) welcomed :
#!/usr/bin/bash
# parameters: $@ = bash (only) scripts that need reindentations.
for script in "$@" ; do
tmpfile="${script}.BEAUTIFY.tmp"
finalfile="${script}.BEAUTIFY"
# optionnal temporisation...
echo "I am about to create ${script}.BEAUTIFY from the bash (I hope) script: ${script} . Press return if OK, ctrl-C if not"
read temporisation
# we output the following commands into a pipe to a subshell bash:
{ sleep 1
echo "
# declare surrounding function . The script has to be bash, but can contain also functions, etc.
# Will lose # comments and blank lines, but maybe also other things... hence the Question on unix.se
ODBEAUTIFIER () {
$(cat "$script")
}
# print if via declare -f, to pretiffy it
declare -f ODBEAUTIFIER > \"${tmpfile}\"
# then get rid of the surrounding ODBEAUTIFIER function:
tail -n +3 \"${tmpfile}\" | tac | tail -n +2 | tac | sed -e 's/ //' > \"${finalfile}\"
# and displays the resulting file
ls -l \"${script}\" \"${finalfile}\"
\rm \"${tmpfile}\" ; # that rm has a backslash to avoid aliases to rm -i
"
} | bash ; # that sub- bash receives the input and interprets it
done
Note/edit: There is a workaround (but with many caveats and dangers) to avoid the "declare -f will lose comments starting with #": but it seems it distracts (… at least one insisting user, see comments below ^^) from the main question (Even tough I cited the many caveats of the workaround, I prefer to remove its mention above as it wasn't at all the point of the question. Curious minds may refer to the edit before now ^^ )
Best Answer
There's a security risk with reading in the script as a function then piping to another shell: If the input file contains an unmatched
}
, then whatever follows it will be executed (and omitted from the output).An unmatched
}
could come about accidentally or maliciously. It would normally cause bash to report a syntax error, but an attacker could hide this (from the user running the beautify script) by ending the file with another, unfinished function:Less important:
You've mentioned that it loses comments starting with
#
. That includes the opening#!/bin/...
, so it may prevent the output files from running.sed -e 's/ //'
strips the first 4 spaces in any line. Those are usually the 4 spaces prepended bydeclare
. Butdeclare
doesn't insert spaces before the lines of a here-document, so this may delete other spaces that were part of the original.You could use
head -n -1
instead oftac | tail -n +2 | tac
. Or you could remove bothtail
s and usesed '1,2d;$d'
.