We all face questions that forget to include their code. Sometimes all of it, sometimes only parts, that make the rest of the question unfortunately incomplete and therefore off-topic.
What if it was possible to remedy that behavior with a simple script? What if said script fits in a single comment, at least in a less featured variant?
Goals
A POSIX compatible script that prints all files in the current directory in the following format:
## File: <path-to-file>
source code line 1
source code line 2
source code line 3
...
Therefore, no bashism (like variable arrays), GNU extensions to find
or similar.
The script must only depend on POSIX variants of sh
, find
and sed
. Shellcheck must pass without errors or warnings.
By default, it should print only C/C++ related files and skip the .git
and build
folders that are often found in those projects. Both options should be configurable via environment variables.
The complete script
#!/bin/sh
FILE_HEADING="## File: %s\n\n"
IGNORED_DIRS="${IGNORED_DIRS:-build .git}"
EXTENSIONS="${EXTENSIONS:-c cc cpp h hpp}"
PRUNE_RULES=""
for dir in ${IGNORED_DIRS}; do
PRUNE_RULES="${PRUNE_RULES} -name ${dir} -prune"
done
RULE_GLUE=""
if [ -n "${PRUNE_RULES}" ]; then
RULE_GLUE="-o"
fi
NAME_RULES=""
for ext in ${EXTENSIONS}; do
if [ -z "${NAME_RULES}" ]; then
NAME_RULES="-name '*.${ext}'"
else
NAME_RULES="${NAME_RULES} -o -name '*.${ext}'"
fi
done
if [ -n "${NAME_RULES}" ]; then
NAME_RULES="\\( ${NAME_RULES} \\)"
fi
sh << EOF
find . ${PRUNE_RULES} ${RULE_GLUE} ${NAME_RULES} \
-exec sh -c "printf '${FILE_HEADING}' {} && sed 's/^/ /' {}" \\;
EOF
Usage:
cd repository
EXTENSIONS=rb IGNORED_DIRS="gem .git" path/to/script.sh
The second sh
call is necessary as find
doesn't work with multiple-options in a single argument. Every option for find
needs to be in its own argument (e.g. find . '-name' '*'
is fine, find . '-name *'
is not).
Wait, I was promised a command that fits in a single comment!
For a comment, we can make some adjustements. First of all, we don't need to prune
, as .git
folders don't contain source code (not counting hooks). However multiple spaces in comments will get replaced by a single one, even in code, so you have to use a tabulator instead:
find . -name '*.hs' -exec sh -c 'printf "## File: %s\n\n" {} && sed "s/^/\t/" {}' \;
You should adjust the file type to the users question, of course. If you're sure that they have GNU find
installed, it gets a little bit easier:
find . -o -name '*.rb' -printf "## File: %P\n\n" -exec sed "s/^/\t/" {} \;
That being said, for some languages like Rust or JavaScript, you really should ignore their additional directories, or at least tell the user to check their post.
Those two variants are also eligible for review, although the latter doesn't follow the POSIX and the settings goals anymore