Customising PS1 to Include a Shell Script
Today – instead of making actual progress in the course – I got lost in the supplementary reading about setting yourself up with a custom prompt. Since most shells come pre-configured with many of the ideas of the blog post already implemented, the only option that really caught my attention was using a shell script inside the PS1 variable. The example given was a script to count the size of regular files in the current directory and show it next to the prompt. I was more interested in the total size of the current directory, including all files in subdirectories, so I set out to try that. This post is more of an answer to the call to post one’s progress, than an actual offer of useful code, since I still don’t deem having the filesize shown important enough to incorporate into my personal prompt.
Step by Step to a Prompt Which Displays File Size
Finished Product First
All this produces is a simple addendum to the prompt, displaying the size of the files in the current directory and its subdirectories. Can be placed anywhere in the custom prompt:
[
]
The Bash Script
To achieve this, one has to write a bash script to recursively sum up filesizes:
#!/bin/bash
calculate_size() {
local directory=$1
local totalsize=0
for filesize in $(find "$directory" -type f -exec stat -c %s {} \; 2>/dev/null); do
((totalsize += filesize))
done
for subdir in $(find "$directory" -type d); do
if [[ "$subdir" != "$directory" ]]; then
((totalsize += $(calculate_size "$subdir")))
fi
done
echo "$totalsize"
}
# Usage example
total=$(calculate_size .)
echo "$total bytes"
Adding the Script to PATH
After making the script executable, one has to include the script itself or its folder into PATH. This can be done by including the following line in ~/.bashrc
, which is where customisation is done on my Ubuntu LTS server, or in whatever file is the correct one for your distribution.
export PATH="$PATH:/path/to/script.sh"
or
export PATH="$PATH:/path/to/scripts/folder"
Customising PS1
Find PS1 in whatever customisation file it is defined in on your system, and add the following snippet anywhere, where you would like the file size to be displayed.
(path/to/your/script.sh)]
Notes
- The Bash script was in part written by me with the knowledge I gained from a previous shell scripting course, and in part written and refined by ChatGPT 3.5
- This by no means has to be the most elegant way to calculate total file size, I am new to shell scripting
- There might very well be cases where the script fails due to special characters or other unexpected input, it has no error catching mechanisms
- It could be further refined to show sizes in bytes/kilobytes/megabytes/… according to the total calculated
- Unfortunately, Lemmy does not seem to support syntax highlighting for code blocks
tl;dr
I talked about how to customise the PS1 prompt in a shell to display the total size of files in the current directory and its subdirectories. This is done by creating a Bash script to calculate the total file size and incorporating it into the PS1 variable. The script should be added to the PATH and the PS1 should be modified to display the file size information.
As an alternative to the script, you can use this one-liner to get the total size of the current directory and all subdirectories:
du -sh | awk '{print $1}'
The
du
command recursively outputs the total size of each subdirectory under the specified path, or under the current directory if no path is specified. The-s
option causes it to output just the total instead of listing all the individual subdirectories. The-h
option gives output in “human readable” units. The output will look something like this:32K .
The
.
means the current directory. If we didn’t specify the-s
option, there would be additional lines with filesizes and directory names listed. However, we only want the32K
part, without the spaces or the directory name. Fortunately there’s another command that’s good for working with data that’s in “table” format, with rows and columns. We use the|
character to specify that we want the output from the first command,du
, redirected into the second command,awk
.The
awk
command has an entire scripting language that you can use, but for our purposes we only need a single statement,'{print $1}'
. This takes the value from the first column of each line and writes it to the output, ignoring the rest. If we used$2
instead of$1
, it would output the second column instead. Columns are assumed to be separated by some number of space or tab characters.Thank you so much for the great explanation and taking the time to reply to my post! That is most certainly a more elegant solution!
The
du
command does exactly what I and even the post author in the linked post to the course intended to do via a script! Though, I can imagine that the author just wanted to provide a quick example script for usage in the prompt.awk
seems pretty interesting. Going a bit off-topic:Awk is a programming language that makes it possible to handle [simple, mechanical data manipulation] tasks with very short programs, often only one or two lines long. An awk program is a sequence of patterns and actions that tell what to look for in the input data and what to do when it’s found (p. iii).1
Probably more needed in 1988 than today (due to fewer alternatives being available) it seems to still have good use cases. Also, there is a second edition in the works, even after 35 years! Last note: I know Brian Kernighan from his appearances on Computerphile 😁 .
1Aho, A. V., Kernighan, B. W., & Weinberger, P. J. (1988). The AWK programming language. Upper Saddle River, NJ: Pearson.
Awk is a great tool to have in your bag, I’m glad you find it interesting. A note on your use case, though - if all you are doing is printing one column,
cut -f 1
is likely more performant.