Ask Dave Taylor
  • Facebook
  • Instagram
  • Linkedin
  • Pinterest
  • Twitter
  • YouTube
  • Home
  • YouTube Videos
  • Top Categories
  • Subscribe via Email
  • Ask A Question
  • Meet Dave
  • Home
  • Linux Shell Script Programming
  • Linux Shell Script: How to Count Executables in the $PATH

Linux Shell Script: How to Count Executables in the $PATH

November 5, 2022 / Dave Taylor / Linux Shell Script Programming / No Comments

I’m taking a Linux shell script programming class and our latest assignment is to count files and executables across all the directories in our PATH. I am stumped. Do you have some pointers to get me going, please?

While the vast majority of our interaction with computers nowadays is through graphical interfaces (think smartphone) or voice (Alexa devices), there are still cases where a command line interface and a keyboard input is the most efficient form of interaction. There are also millions of systems on the Internet that are running Linux, and while Linux has graphical interface options, a lot of developers prefer to crack open the command line for their power tasks.

I’m also a long-time Linux user, and Unix before that, so I have a very positive association with the command line too, which is why I’m happy to help you out with this. Heck, I’ve written quite a few books about Unix and Linux too, including the best-selling Wicked Cool Shell Scripts that I recommend both to you and your instructor. 😁

Okay, back on task! Now, let’s start breaking down the task, because, like any other programming project, the key to success is to divide and conquer. There are three pieces to this script that will need to be solved: How to count total files, how to count executables, and how to step through directories listed in the PATH. Let’s check it out, step by step…

HOW TO STEP THROUGH YOUR $PATH

There are a half-dozen or so system settings that are set as part of your interactive shell instantiation, including HOME, USER, SHELL, and PATH. All system variables of this nature are in all-caps, and you can see every one in your own interactive shell by typing the command env. You can try it yourself to see what’s shown, but it’s typically 12-20 different variables, including a few oddities like _=/usr/bin/env.

The most important is the PATH and that can be very easily displayed as shown:

$ echo $PATH
/opt/local/bin:/opt/local/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:
/bin:/usr/sbin:/sbin:/Applications/VMware Fusion Tech Preview.app/Contents/Public

I’m running these tests on my Mac system, which has a full Linux-esque system accessible through the Terminal app, which is why I might have a few that are different to what you’ll see, most notably the VMware Fusion directory. No worries, the script is going to be portable, which is one of the great joys of Linux, Unix, and its related operating systems.

The challenge with stepping through the directories in the PATH is that the fields are not separated by spaces but rather by the colon (“:”) symbol. There are a number of ways to solve this, the most common of which is to change the Internal Field Separator (IFS) value within the shell, but that leads to other problems, so instead I’m going to use the read command and an input redirect at the end of the for loop. Here’s the script fragment I would use to step through my PATH:

while read -d ':' dir
do
   echo "$dir"
done <<< "$PATH:"

That’s easy enough, and the “<<<” notation is what’s known as a “here” notation, just handing the subsequent value to the loop as if it were standard input. Note the trailing “:” to ensure that it sees the last PATH value too! As is, here’s what I see upon execution:

$ sh count-executables.sh
/opt/local/bin
/opt/local/sbin
/usr/local/bin
/System/Cryptexes/App/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
/Applications/VMware Fusion Tech Preview.app/Contents/Public

That’s exactly what I want because once I can isolate each directory, I can then use that as a parameter to a different command that can count files or executables. We’ll get to that next…

HOW TO COUNT FILES IN A DIRECTORY

The next puzzle to solve is how to count how many files (not folders!) are in a directory and how many are marked as executable. There are a number of ways to do that, including using the ls command, but I think find is your best bet, specifically using the -type parameter. A quick peek at the find man page reveals its options:

find man page - type parameter detail

This will let you count files in a directory, though there’s no option to count executables. Okay, divide and conquer. For this block the code is fairly straightforward once you know this option for find, but let’s start with a command line test:

$ find /usr/bin -type f -depth 1 | wc -l
894

Sheesh, 894 files just in /usr/bin. Impressive. You’re probably wondering what the -depth 1 does that’s added here; it’s to ensure that the count doesn’t include files that might be in subdirectories because by default find examines “the specified location and all subdirectories therein”.

Also, wc -l is, of course, an easy way to get a count of lines output by the previous portion of the command pipe (‘-l‘ counts lines, the wc command has other useful capabilities too).

Adding this to our code fragment:

while read -d ':' dir
do
  echo "$dir"
  find "$dir" -type f -depth 1 | wc -l
done <<< "$PATH:"

The result has a very interesting output:

$ sh count-executables.sh
/opt/local/bin
find: /opt/local/bin: No such file or directory
0
/opt/local/sbin
find: /opt/local/sbin: No such file or directory
0
/usr/local/bin
0
/System/Cryptexes/App/usr/bin
1
/usr/bin
894
/bin
37
/usr/sbin
find: /usr/sbin/authserver: Permission denied
197
/sbin
40
/Applications/VMware Fusion Tech Preview.app/Contents/Public
find: /Applications/VMware Fusion Tech Preview.app/Contents/Public: No such file or directory
0

What’s the story behind those errors? Turns out that it’s entirely possible to have a directory specified in PATH that doesn’t actually exist. It’s sloppy and should be fixed, but it also might be set deep in the OS where you have no ability to fix it. This means it’s up to our code to test and ensure that the folder exists before we try to count entries with find. That can be accomplished with an if-then test:

while read -d ':' dir
do
  if [ -x "$dir" ] ; then
    echo "$dir"
    find "$dir" -type f -depth 1 | wc -l
  else
    echo "$dir not found"
  fi
done <<< "$PATH:"

This includes an error message with the else clause but you can skip this if you want (or for bonus points accumulate the names of all these directories and output it with your summary data). I’ll show it once, then skip it for subsequent output in this tutorial to keep things reasonably succinct.

Now when I run the script, the output’s a bit less clumsy:

$ sh count-executables.sh
/opt/local/bin not found
/opt/local/sbin not found
/usr/local/bin
0
/System/Cryptexes/App/usr/bin
1
/usr/bin
894
/bin
37
/usr/sbin
find: /usr/sbin/authserver: Permission denied
197
/sbin
40
/Applications/VMware Fusion Tech Preview.app/Contents/Public not found

Handling error conditions within a script is a must, and in this instance also helps ensure an accurate result.

WHAT ABOUT SYMBOLIC AND HARD LINKS?

Another hiccup above is that directories like /usr/local/bin aren’t empty, but all of the contents therein are links, not actual files, according to how find defines things:

$ ls -l /usr/local/bin
total 0
lrwxr-xr-x 1 root wheel 68 Jun 13 21:18 prl_convert@ -> /Applications/Parallels Desktop.app/Contents/MacOS/parallels_wrapper
lrwxr-xr-x 1 root wheel 68 Jun 13 21:18 prl_disk_tool@ -> /Applications/Parallels Desktop.app/Contents/MacOS/parallels_wrapper
lrwxr-xr-x 1 root wheel 68 Jun 13 21:18 prl_perf_ctl@ -> /Applications/Parallels Desktop.app/Contents/MacOS/parallels_wrapper
lrwxr-xr-x 1 root wheel 62 Jun 13 21:18 prlcore2dmp@ -> /Applications/Parallels Desktop.app/Contents/MacOS/prlcore2dmp
lrwxr-xr-x 1 root wheel 68 Jun 13 21:18 prlctl@ -> /Applications/Parallels Desktop.app/Contents/MacOS/parallels_wrapper
lrwxr-xr-x 1 root wheel 58 Jun 13 21:18 prlexec@ -> /Applications/Parallels Desktop.app/Contents/MacOS/prlexec
lrwxr-xr-x 1 root wheel 68 Jun 13 21:18 prlsrvctl@ -> /Applications/Parallels Desktop.app/Contents/MacOS/parallels_wrapper

If you want to count those as files (which might be something that needs clarifying by your teacher) then it’s doable, but the find command in our script gets just a bit more complex:

find "$dir" ( -type f -or -type l ) -depth 1 | wc -l

In other words, we’re going to count files of type ‘f’ or of type ‘l’. Don’t need to account for links? Remove the entire OR statement.

HOW TO SUM UP NUMBERS IN A SCRIPT

We can now identify the number of files in each directory, but how do we sum up these values as we go? The answer to that is to use some of the shell’s built-in math capabilities. The classic way to do that is:

((sum=$sum+$value))

The wrinkle is that we also need to assign the output of the find|wc to a variable so we can add it to the summating value. Doable, and all reflected in this updated fragment:

while read -d ':' dir
do
  if [ -x "$dir" ] ; then
    echo "$dir"
    count="$(find "$dir" -type f -depth 1 | wc -l)"
    echo " $count"
    (( files=$files+$count ))
  else
    echo "$dir not found"
  fi
done <<< "$PATH:"

That’s much of the project solved, with a few tweaks that I’ll show at the end, including the final output command.

COUNTING EXECUTABLE FILES IN A DIRECTORY

The last challenge to solve is how to count executables. Disappointingly, find doesn’t have that as an option with the -type parameter, but it turns out that the test command (as utilized by its alias ‘[‘ in scripts) has exactly what we seek with the ‘-x’ conditional. In other words:

if [ -x $file ] ; then
   echo $file is executable
fi

can be directly translated into a script fragment (with numbers summed up too) as shown:

for file in $(ls "$dir"|sed 's/ /~~/g') ; do
  file="$(echo $file|sed 's/~~/ /g')"
  if [ -x "$dir/$file" ] ; then
    ((executable=$executable+1))
  fi
done

In this instance, ‘executable’ is counting executables in the current directory, and ‘execs’ is the overall summary. Notice the use of sed in the loop? It’s to protect any filenames that have spaces in them: Each space is changed to a “~~” sequence, then immediately changed back once the individual entries have been extracted from the ls output. A common script technique!

And that’s it. Here’s my full script:

#!/bin/sh

# count executables across each directory in the PATH

files=0 # summarize total files found
execs=0 # summarize total executables

dir=$HOME

while read -d ':' dir
do
executable=0
if [ -x "$dir" ] ; then

echo "$dir"

# total files
count="$(find "$dir" \( -type f -or -type l \) -depth 1 | wc -l)"
echo " files in directory: $count"
((files=$files+$count ))

# executables

for file in $(ls "$dir"|sed 's/ /~~/g') ; do
file="$(echo $file|sed 's/~~/ /g')"
if [ -x "$dir/$file" ] ; then
((executable=$executable+1))
fi
done
echo " executables in directory: $executable"
((execs=$execs+$executable))
fi
done <<< "$PATH:"

echo "Total files found across PATH = $files, with $execs executable."

exit 0

And here’s the output with my Mac system:

$ sh count-executables.sh
/usr/local/bin
  files in directory: 7
  executables in directory: 7
/System/Cryptexes/App/usr/bin
  files in directory: 1
  executables in directory: 1
/usr/bin
  files in directory: 933
  executables in directory: 933
/bin
  files in directory: 37
  executables in directory: 37
/usr/sbin
  files in directory: 227
  executables in directory: 224
/sbin
  files in directory: 62
  executables in directory: 62
Total files found across PATH = 1267, with 1264 executable.

That’s it. Mission accomplished. Now, good luck with your own coding efforts!

Pro Tip: I’ve been writing about Linux scripting for years. I even wrote a book about it! Please check out my Linux help library for lots more tutorials, including an area specifically on Linux shell script programming help!

About the Author: Dave Taylor has been involved with the online world since the early days of the Internet. Author of over 20 technical books, he runs the popular AskDaveTaylor.com tech help site. You can also find his gadget reviews on YouTube and chat with him on Twitter as @DaveTaylor.

Let’s Stay In Touch!

Never miss a single article, review or tutorial here on AskDaveTaylor, sign up for my fun weekly newsletter!
Name: 
Your email address:*
Please enter all required fields
Correct invalid entries
No spam, ever. Promise. Powered by FeedBlitz
Please choose a color:
Starbucks coffee cup I do have a lot to say, and questions of my own for that matter, but first I'd like to say thank you, Dave, for all your helpful information by buying you a cup of coffee!
learn shell scripting, linux scripts, shell scripts

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Search

Recent Posts

  • How to Enlarge Font Size in Apple’s Books App on the iPad
  • Chromebook Owner’s Guide to Antivirus & Anti-Malware Solutions
  • Everything You Need to Know about Apple’s Clean Energy Charging
  • How Can I Watch Free Classic Movies on my Windows PC?
  • How Can I Maximize Online Privacy with a VPN Connection?

On Our YouTube Channel

TWT Audio REVO TW310 Budget Headset -- DEMO & REVIEW

iClever Bluetooth 34-Key Number Pad Keyboard -- REVIEW

Categories

  • AdSense, AdWords, and PPC Help (106)
  • Amazon, eBay, and Online Shopping Help (164)
  • Android Help (228)
  • Apple iPad Help (148)
  • Apple Watch Help (53)
  • Articles, Tutorials, and Reviews (346)
  • Auto Tech Help (17)
  • Business Advice (200)
  • ChromeOS Help (34)
  • Computer & Internet Basics (782)
  • d) None of the Above (166)
  • Facebook Help (384)
  • Google, Chrome & Gmail Help (188)
  • HTML & Web Page Design (247)
  • Instagram Help (49)
  • iPhone & iOS Help (625)
  • iPod & MP3 Player Help (173)
  • Kindle & Nook Help (99)
  • LinkedIn Help (88)
  • Linux Help (174)
  • Linux Shell Script Programming (90)
  • Mac & MacOS Help (914)
  • Most Popular (16)
  • Outlook & Office 365 Help (33)
  • PayPal Help (68)
  • Pinterest Help (54)
  • Reddit Help (19)
  • SEO & Marketing (82)
  • Spam, Scams & Security (96)
  • Trade Show News & Updates (23)
  • Twitter Help (222)
  • Video Game Tips (66)
  • Web Site Traffic Tips (62)
  • Windows PC Help (951)
  • Wordpress Help (206)
  • Writing and Publishing (72)
  • YouTube Help (47)
  • YouTube Video Reviews (159)
  • Zoom, Skype & Video Chat Help (62)

Archives

Social Connections:

Ask Dave Taylor


Follow Me on Pinterest
Follow me on Twitter
Follow me on LinkedIn
Follow me on Instagram


AskDaveTaylor on Facebook



microsoft insider mvp


This web site is for the purpose of disseminating information for educational purposes, free of charge, for the benefit of all visitors. We take great care to provide quality information. However, we do not guarantee, and accept no legal liability whatsoever arising from or connected to, the accuracy, reliability, currency or completeness of any material contained on this site or on any linked site. Further, please note that by submitting a question or comment you're agreeing to our terms of service, which are: you relinquish any subsequent rights of ownership to your material by submitting it on this site. Our lawyer says "Thanks for your cooperation."
© 2023 by Dave Taylor. "Ask Dave Taylor®" is a registered trademark of Intuitive Systems, LLC.
Privacy Policy - Terms and Conditions - Accessibility Policy