Sid M. answered 04/30/21
Studied Computer Science and Engineering at University of Washington
This was a fun exercise!
For the bash script, below, I've added line numbers so that I can point out features in my description. Note that since I didn't have any .html files laying around, I changed the extension sought by the script from ".html" to ".txt".
Let's start with the main body of the script, the for-loop on lines 15-20. This is very straight forward, in that it:
- first finds all files matching the path "*.txt" (i.e., all files that end in .txt) and, one at a time, replaces the bash variable f with a path.
- It creates another variable, n, which is the original path less any possible directory part, and without the .txt extension as well, i.e. the name of the file of the path, f. (The basename utility is pretty helpful, here.)
- It creates a 3rd variable, r, which is the result of calling the function rev (above) with the filename part, r. *This* is what takes the filename (r) and reverses the characters in it.
- Finally, it mv's (renames) the path, f, to $r.txt (the reversed name and the original .txt extension).
So, now we come to the meat of the solution, function rev, between lines 3-13.
First, bash allows us to create functions within scripts, which act like locally-declared/defined scripts. I'm taking advantage of this because my approach to the solution is to use recursion to reverse a string (the filename).
Here's the basic idea:
- If the string (argument) consists of a character (let's call it Head), followed by 0 or more characters (let's call this part the Midl), followed by [just] 1 more character (the Tail), then the result is simply the Tail, followed by Midl after it has been reversed, followed (finally) by the Head. Notice the recursion on Midl. Note, too, that the pattern matches any string of *at* *least* 2 characters; otherwise, it doesn't match.
- Otherwise, the string argument isn't at least 2 characters (i.e. it's 0 or 1), and so it cannot be reversed (or, rather, it is *already* reversed), so the result is just the string, itself.
So, How do we do this?
Line 4 has an expression which matches its (only) expected argument ($1) to a regular expression pattern the matches 2-or-more characters, in 3 parts; each part is delimited by parentheses). If the pattern matches, then we execute the statements in lines 6-10; otherwise, we simply echo the argument (per #2, above).
If the pattern matches, lines 6-10 embody #1 from above. After execution of an expression like on line 4, bash remembers the parts of the string that match and are delimited by parentheses, in an array variable called BASH_REMATCH. The part matched by the first set of parentheses is in BASH_REMATCH[1], and so on. So, Head becomes BASH_REMATCH[1], Midl becomes BASH_REMATCH[2] as modified by a recursive call to rev, and Tail becomes BASH_REMATCH[3]. All that's left is to echo each of the 3 parts in the proper order and return.
That's it!