Real World Solutions: Updating Ebooks

by benjamin@tty1.blog at

So far, this blog has largely been tutorials on how to use particular commands or workflows. I'll keep doing that, but I also want to highlight some real-world problems that can easily be solved with some knowledge of shell scripting and the command line.

To start off, here's how I used the find command to create a script for Nantucket E-Books to help them easily update the code for all of their books at once.

The Setup

While I didn't have the exact file structure to work from, based on Nicholas's description I was able to infer that it looked something like this:

.
├── author1
│   ├── book1
│   │   └── assets
│   │       └── js
│   └── book2
│       └── assets
│           └── js
├── author2
│   └── book1
│       └── assets
│           └── js
├── author3
│   ├── book1
│   │   └── assets
│   │       └── js
│   ├── book2
│   │   └── assets
│   │       └── js
│   └── book3
│       └── assets
│           └── js
├── author4
│   ├── book1
│   │   └── assets
│   │       └── js
│   └── book2
│       └── assets
│           └── js
└── author5
    ├── book1
    │   └── assets
    │       └── js
    ├── book2
    │   └── assets
    │       └── js
    ├── book3
    │   └── assets
    │       └── js
    └── book4
        └── assets
            └── js

Within each book's folder, the same three JavaScript files needed to be updated to the newest version.

the solution

My solution was a simple shell script:

#!/bin/sh

subdirs="$(find "$PWD" -mindepth 2 -maxdepth 2 -type d)" # Get the full paths of all second-level subdirectories

echo "$subdirs" | while read subdir; do # for each selected subdirectory, do the following
	cd "$subdir" # moves into the correct directory

	# do your actions here

done

This solution let him add the actual commands to copy the new files at the indicated location, but would make sure whatever he put there would be executed in every book's folder. For example:

cp ~/code/updated-file.js ./assets/js/file.js

The above would take the updated file and copy it to the location it belongs in each book's subdirectory.

breaking it down

Let's break this solution down a little.

To start off, I wanted to get every book's path and store it to a variable, subdirs. The find command is ideal for that purpose.

Combined, -mindepth 2 and -maxdepth 2 essentially just say "find all results that are exactly two subdirectories away". In our case, this perfectly matches all book directories, since they're subdirectories of the author directories, but keeps the script from matching the assets and js directories, since those are more than two subdirectories away.

Let's test it:

/tmp/tmp.UkyqnYccbh] subdirs="$(find "$PWD" -mindepth 2 -maxdepth 2 -type d)"
/tmp/tmp.UkyqnYccbh] echo "$subdirs"
/tmp/tmp.UkyqnYccbh/author2/book1
/tmp/tmp.UkyqnYccbh/author4/book2
/tmp/tmp.UkyqnYccbh/author4/book1
/tmp/tmp.UkyqnYccbh/author1/book2
/tmp/tmp.UkyqnYccbh/author1/book1
/tmp/tmp.UkyqnYccbh/author3/book2
/tmp/tmp.UkyqnYccbh/author3/book1
/tmp/tmp.UkyqnYccbh/author3/book3
/tmp/tmp.UkyqnYccbh/author5/book4
/tmp/tmp.UkyqnYccbh/author5/book2
/tmp/tmp.UkyqnYccbh/author5/book1
/tmp/tmp.UkyqnYccbh/author5/book3

That is, indeed, all of the exact directories we want!

Next, we want to loop through all of these folders. In my last article, I mentioned the strategy of piping a list to a while loop, which I've done again here.

echo "$subdirs" | while read subdir; do
	# …
done

An important note is that pipes like this create subshells, meaning that any variables I set within the loop cannot affect the rest of the script. For this use case, that doesn't matter (since created files/directories will of course remain after the subshell finishes), but it's good to be aware of when adapting this script to your own purposes.

Now that we are in the loop, we'll move into the subdirectory that's currently being processed:

cd "$subdir"

Easy peasy. As we mentioned, anything else we want done while in this folder can now be added.

the results

Nicholas's immediate response?

I just updated the software and stylesheets for forty-eight e-books on the site with one command.

He's written a blog post of his own that mentions this solution, which is also worth reading. And while you're there, check out the platform, it's a great and easily accessible platform to read books for free from any device, with built-in audiobooks. It's a great project, and I'm proud to have been able to lighten the load of keeping it running.

conclusion

I'll leave off there. If you have solutions to real-world problems of your own to continue this series or a real-world problem you need help solving with the shell, I'd love if you'd send me a message! It can be like this article, where I wrote about a solution to someone else's problem, or you can write a guest article for publication on this blog.

My email (and PGP key!) are below, I'd love to talk through your ideas with you. See you next time!


Benjamin Hollon

benjamin@tty1.blog

Benjamin Hollon is a writer and citizen of the world with far too many hobbies. Besides writing for his blogs, he codes, plays and composes music, writes poetry and fiction, and more. He is currently studying Communications and Professional Writing at Texas A&M.

He is active on Mastodon.

Email Public Key


Comments

Comment via Fediverse


Liked what you read?

What's next?