I have the following function to count the number of files in a directory, within my bash script.

file_count() {
  no_of_files=$(find "$1" -maxdepth 1 -type f -printf '.' | wc -c)

I'd like to use it repeatedly on different directories and save the count into a variable for each directory. Currently to do this, I use

file_count $somedir

I'm aware that I'm setting the no_of_files variable outside of the function each time, and would like to make it local to the function, not settign an intermediate variable in the main script. This is just in case there's some mistake meaning that the variable doesn't change between calls of the function (mistyping the function name maybe), and the old value of no_of _files is used.

If my function were:

file_count() {
  local no_of_files=$(find "$1" -maxdepth 1 -type f -printf '.' | wc -c)

How would I easily set these directory count variables?

  • So you are basically asking how a function may return a value in Bash?
    – Byte Commander
    Sep 14, 2016 at 15:30
  • I guess so, I know it seems really stupid, and I know about the return keyword, but something doesn't seem to be working with my use of it.
    – Arronical
    Sep 14, 2016 at 15:33
  • If I put return "no_of_files" at the end of the function, then reference it with $? I get a completely spurious value.
    – Arronical
    Sep 14, 2016 at 15:35
  • just to point out, that you don't really need a function in this case, unless you reuse that same find+wc structure over and over. You also don't need pipe - find command has -exec flag to call external commands on files that it finds Sep 14, 2016 at 15:53
  • @Serg tomorrows question will be about the best way to count the number of files in a directory!
    – Arronical
    Sep 14, 2016 at 15:55

2 Answers 2


Bash functions are not like functions on other programming languages, they are more like commands. This means they have no classical return value, but

  • an exit/return code. This is an integer number in the range 0-255, where 0 means "success" and every other value represents an error. If you try to specify a number outside this range, it will be taken modulo 256 (add or subtract 255 from your number until it fits the range 0-255).

    This code is automatically set to the return code of the last statement that got executed inside the function, unless you manually set it using the return command, like this:

    return 1
  • output streams. Each Bash function can write arbitrary strings to the output streams (STDOUT and STDERR), just like normal scripts. The output can either be directly from the commands you run in the function, or set manually by using echo.

    But instead of letting this output get displayed in the console, you can capture it when you run the function, e.g. using Bash's command substitution syntax, and store it in a variable in your main script:

    example_function() {
        # do something useful
        echo "return this message"

So your code would have to look like this:

file_count() {
    find "$1" -maxdepth 1 -type f -printf '.' | wc -c
    # the line above already prints the desired value, so we don't need an echo

files_in_somedir="$(file_count "$somedir")"

See Return value in bash script (on Stack Overflow) for more info.

  • Thanks, I realised that I was hideously over-complicating things as soon as you commented, but as I can't find anything like this on AU, I think it may be useful to other users in future.
    – Arronical
    Sep 14, 2016 at 15:47
  • I also tried to use return to display the value of the variable, when this value was 633, it was returning 121, return can only display values between 0-255. $(( 633 % 256 )) = 121.
    – Arronical
    Sep 14, 2016 at 15:51
  • That's just what I said. However, I'll add that numbers outside that range will be adapted using the modulo operation.
    – Byte Commander
    Sep 14, 2016 at 15:55
  • Extraneous detail in my comment, I was just glad that I understood why I was getting that number.
    – Arronical
    Sep 14, 2016 at 15:57

I'm a C++ programmer, so I like to mimic the "getter and setter" philosophy, where you use tiny little functions to get and set the value of a variable. I know there are some non-portable solutions out there like new versions of declare, but I like writing only portable code. The downside to using getters and setters is that you need to create a function (or two functions) for every value you want to manage. So... I made a "factory function" that handles creating getters/setters for you (below). Then, you just drop the equals sign for setting, and everything else looks pretty similar (see usage)... except now, you can pass "pointer-like things" into functions.

makeGetSet() {
. /dev/fd/0 <<END_FUNC
${1}Val()  { [ "\${1}" ] && ${1}="\${1}" || echo "\${${1}}"; }


Setup: makeGetSet myVariable
Set: myVariableVal newValue
Get: anotherVariable="`myVariableVal`"
Print: myVariableVal

It does not require any particular shell (100% POSIX) with special features like indirection or namerefs, or the declare utility. You just pass in your variable name to makeGetSet, and your getter/setter function has that same name with a "Val" at the end (e.g. myVariableVal). Tested with bash and dash.

For your specific question, you would use it like this:

makeGetSet files_in_somedir

file_count() {
  "${2}" $(find "$1" -maxdepth 1 -type f -printf '.' | wc -c)

file_count "/some/directory" files_in_somedirVal
  • 1
    I wish people would leave at least a brief comment with downvotes... I thought that this has been something lacking in the shell for DECADES now, and look how easy, powerful, and efficient it is once somebody has made the "factory function" for you !!! If anybody is still trolling, please tell me WHAT you don't like, so I can come up with something better !! Being able to do something like "pass by reference" to a function and change its value is a HUGE programming feature.
    – Sean
    May 18, 2021 at 18:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.