1. Overview

In Linux, we can usually display a file’s modified date or timestamp by listing its parent directory. The other common way to get this information is by using the stat command. Sometimes, it might be handy or more efficient to display this information while searching for files.

In this tutorial, we’ll look at how to display the modified date of files on the output of the find command.

2. Using the printf Option of the find Command

First, let’s take a look at the default output of the find command, which displays only the names of the files found:

$ find . -name '*json*'
./json-folder
./.eslintrc.json
./file with-space.json
./package.json
./tsconfig.json

We can easily make the output more useful by using the printf option. The GNU version of the find command includes an option or flag named printf. It accepts one argument, which is the format that’ll be interpreted and outputted to stdout. The interpreted output replaces the default output of the command, and the interpretation is done for each file found.

The format consists of escapes that start with a backslash (\) and directives that start with a percent (%). We use the %t and %Tk directives to display the last modification time of a file. Let’s look at an example usage of the printf option where we print the names of the files found and their last modification times:

$ find . -name '*json*' -printf "%-25p %t\n"
./json-folder             Mon Aug 23 03:37:42.1869447530 2021
./.eslintrc.json          Mon Aug  9 00:09:14.6669121720 2021
./file with-space.json    Mon Aug 23 02:39:25.1991621890 2021
./package.json            Mon Aug  9 00:08:08.5493444190 2021
./tsconfig.json           Mon Aug  9 00:08:58.9590148590 2021

In the above example, we’re specifying something called a field width inside the filename printf directive. The unit for the width of a directive is the number of characters. If the width of the interpreted value for that directive is less than the specified width, then it is padded with whitespace. The field width of a directive is specified after the % sign of a directive. The hyphen (-) between the % sign and the width specifies that the interpreted value should be left-padded.

The full list of escapes and directives can be found in the man pages, but let’s take a look at some of them:

  • \n – newline
  • \t – horizontal tab
  • %p – file’s name
  • %M – file’s permissions
  • %Tk – file’s last modification time in a format specified by k. The man page of the find command contains the full list of possible values for k.

2.1. Custom Helper Function

We can add a helper bash function into our ~/.bashrc file to make using the printf option more efficient. The function searches for files that contain a specific word in their names and displays the modified times of the files alongside other information. Let’s look at the function:

function findnamed {
    find ${2:-.} -name "*$1*" -printf "%M %-6u %-6g  %-${3:-40}p %TY-%Tm-%Td %TH:%TM\n"
}

The above function expects three arguments. The first argument is the keyword to use when searching files by name. The second one is the directory to search in, and the default value is the current directory. The third one is the field width of the filename directive inside the printf option, and the default value is 40.

Now, let’s look at how we can use the function by providing only the search keyword:

$ findnamed '*json'
drwxrwxr-x haben  haben   ./json-folder                            2021-08-23 03:37
-rw-rw-r-- haben  haben   ./.eslintrc.json                         2021-08-09 00:09
-rw-rw-r-- haben  haben   ./file with-space.json                   2021-08-23 02:39
-rw-rw-r-- haben  haben   ./package.json                           2021-08-09 00:08
-rw-rw-r-- haben  haben   ./tsconfig.json                          2021-08-09 00:08

We can also call the function by providing the directory to search in and the field width of the filename directive:

$ findnamed '*json' project-root/ 35
drwxrwxr-x haben  haben   project-root/json-folder            2021-08-23 03:37
-rw-rw-r-- haben  haben   project-root/.eslintrc.json         2021-08-09 00:09
-rw-rw-r-- haben  haben   project-root/file with-space.json   2021-08-23 02:39
-rw-rw-r-- haben  haben   project-root/package.json           2021-08-09 00:08
-rw-rw-r-- haben  haben   project-root/tsconfig.json          2021-08-09 00:08

3. Using the xargs Command With the find Command

The xargs command is used to execute commands from standard input. We can use it in our case to execute commands like ls and stat on the find command results to display the modified time of a file. A command can be executed for each file found by the find command by piping the results of the command into xargs.

The default behavior of xargs will not work with the output of the find command if there are filenames that contain spaces. We need to tell xargs to only use \n as a delimiter to overcome this issue. This can be done by using the -d option that is found on the GNU version of xargs.

Similarly, we can also do this by translating newline characters (\n) into null characters (\0) using the tr command and using the -0 option of the xargs command.

Let’s look at how to use xargs to call the stat command for each file found by find:

$ find . -name "*json*" | xargs -d '\n' stat -c "%-25n %y"
./json-folder             2021-08-23 03:37:42.186944753 +0300
./.eslintrc.json          2021-08-09 00:09:14.666912172 +0300
./file with-space.json    2021-08-23 02:39:25.199162189 +0300
./package.json            2021-08-09 00:08:08.549344419 +0300
./tsconfig.json           2021-08-09 00:08:58.959014859 +0300

We can also use xargs to call the ls command for each file found by find:

$ find . -name "*json*" | xargs -d '\n' ls -ld
-rw-rw-r--. 1 haben haben 2259 Aug  9 00:09  ./.eslintrc.json
-rw-rw-r--. 1 haben haben 2259 Aug 23 02:39 './file with-space.json'
drwxrwxr-x. 2 haben haben 4096 Aug 23 03:37  ./json-folder
-rw-rw-r--. 1 haben haben 2259 Aug  9 00:08  ./package.json
-rw-rw-r--. 1 haben haben 2259 Aug  9 00:08  ./tsconfig.json

4. Using the exec Option of the find Command

The exec option of the find command can be used similarly to the xargs command used above. But, using the exec option might be slower than xargs, and it’s more difficult to read. Let’s look at how we can use the exec option to execute the stat commands for each file found by the find command:

$ find . -name "*json*" -exec stat -c "%-25n %y" {} \;
./json-folder             2021-08-23 03:37:42.186944753 +0300
./.eslintrc.json          2021-08-09 00:09:14.666912172 +0300
./file with-space.json    2021-08-23 02:39:25.199162189 +0300
./package.json            2021-08-09 00:08:08.549344419 +0300
./tsconfig.json           2021-08-09 00:08:58.959014859 +0300

We can also use the exec option to call the ls command for each file found by find:

$ find . -name "*json*" -exec ls -ld {} \;
drwxrwxr-x. 2 haben haben 4096 Aug 23 03:37 ./json-folder
-rw-rw-r--. 1 haben haben 2259 Aug  9 00:09 ./.eslintrc.json
-rw-rw-r--. 1 haben haben 2259 Aug 23 02:39 './file with-space.json'
-rw-rw-r--. 1 haben haben 2259 Aug  9 00:08 ./package.json
-rw-rw-r--. 1 haben haben 2259 Aug  9 00:08 ./tsconfig.json

5. Conclusion

In this tutorial, we’ve seen different ways to include the modified dates of files in the search result of the find command. We’ve also seen how to customize the output of the find command to include various information.