I'm writing a bash script to search C source files and find the lines where I missed the void keyword (unlike in C++, in C, empty parameter lists have to be indicated with the void keyword).
I read that I shouldn't use for
but while
: https://mywiki.wooledge.org/DontReadLinesWithFor
I find that for
has an easier to follow, top-down structure (first I write the command that produces the items to be iterated, then I write what to do with each).
I understand that if a filename contained a newline it would cause trouble in case of for
; however, with IFS=$'\n'; set -f
I would think all other problems are solved.
My code using for:
#!/bin/bash
returnTypeOpt_BRE='\([a-zA-Z_][a-zA-Z0-9_]\{0,\}[* ]\{1,\}\)\{0,1\}'
spaceOpt_BRE=$'[ \t\r]\\{0,\\}'
functionName_BRE='\([a-zA-Z_][a-zA-Z0-9_]\{0,\}\)'
declarationMissingVoid_BRE="^$returnTypeOpt_BRE$spaceOpt_BRE$functionName_BRE$spaceOpt_BRE($spaceOpt_BRE)$spaceOpt_BRE;$spaceOpt_BRE\$"
targetFolder_Path="1ドル"
if [ $# -eq 0 ]; then
targetFolder_Path="."
fi
IFS=$'\n'; set -f; for file in $( find "$targetFolder_Path" -name '*.c' -or -name '*.h' ); do
printf "%s\n" "$file"
for line in $( grep --basic-regex --regexp=$declarationMissingVoid_BRE $file ); do
printf "\t>%s\n" "$line"
done
done; unset IFS; set +f
My code using while:
#!/bin/bash
returnTypeOpt_BRE='\([a-zA-Z_][a-zA-Z0-9_]\{0,\}[* ]\{1,\}\)\{0,1\}'
spaceOpt_BRE=$'[ \t\r]\\{0,\\}'
functionName_BRE='\([a-zA-Z_][a-zA-Z0-9_]\{0,\}\)'
declarationMissingVoid_BRE="^$returnTypeOpt_BRE$spaceOpt_BRE$functionName_BRE$spaceOpt_BRE($spaceOpt_BRE)$spaceOpt_BRE;$spaceOpt_BRE\$"
targetFolder_Path="1ドル"
if [ $# -eq 0 ]; then
targetFolder_Path="."
fi
while IFS=; read -u 3 -r -d $'0円' file; do
printf "%s\n" "$file"
while IFS=; read -u 4 -r line; do
printf "\t>%s\n" "$line"
done 4< <( grep --basic-regex --regexp=$declarationMissingVoid_BRE $file )
done 3< <( find "$targetFolder_Path" -name '*.c' -print0 -or -name '*.h' -print0 )
So, for me both scripts work correctly, and produce the same result.
Beyond the "filenames with newlines" issue is there anything else that would make while
better? Can you show me a test case?
If I had to solve similar but different (possibly more complex) tasks would I have problems with for
?
1 Answer 1
I'm writing a bash script to search C source files and find the lines where I missed the void keyword
This alone suggests that your approach is very problematic. To do this properly you'd effectively need to write most of a C parser, and that isn't a good use of your time. There are other approaches that would get you more mileage and accuracy:
- Double-check that your compiler (gcc?) for sure doesn't have warnings that cover your use-case; if it does, then simply compile and look at the output.
- Failing that, reuse a parser. I recommend the Clang AST.
Bash is just the hideously wrong tool for this. Save yourself the pain of writing regexes that are both complex and likely missing many edge cases.
-
\$\begingroup\$ GCC doesn't have warnings for this. If it did, that would be great, but it doesn't. \$\endgroup\$S.S. Anne– S.S. Anne2020年03月15日 17:25:35 +00:00Commented Mar 15, 2020 at 17:25
-
\$\begingroup\$ My C source files are quite simple, and I'm not afraid of missing some edge cases. On the other hand, I would like to know how to search regex patterns in multiple files with bash scripts. \$\endgroup\$z32a7ul– z32a7ul2020年03月15日 18:35:31 +00:00Commented Mar 15, 2020 at 18:35