1. Overview
There are cases when we want to check if a certain file type exists or not in a directory. For example, we may want to see whether there are PNG images in a directory. That way, we can collect all PNG files across a specified storage location.
In this tutorial, we’ll discuss a variety of ways to check the file types in a directory.
2. Example Directory
The examples in this tutorial are using a directory named directory that has the following content:
$ ls -1 directory/
handlers.py
hello2.sh
hello-world.sh
images
project_source_code.zip
python_code.py
ReactART.js
3. Checking the File Type with ls
We often determine a file type by looking at its extension. Using this approach, we can list all files with a specific file type with the ls command:
$ ls directory/*zip
directory/project_source_code.zip
But we all know that a file can hide with a faux extension. For example, a ZIP file can have the .txt extension:
$ mv directory/project_source_code.zip directory/project_source_code.txt
$ ls directory/*txt
directory/project_source_code.txt
However, checking the file type based on the extension is a reasonable approach. Later, we’ll discuss a way to check the file type of a file based on its content, not its extension.
What if we want to check the directory file type? A directory usually doesn’t have an extension. We can use the -d flag and */ in the argument:
$ ls -d directory/*/
directory/images/ directory/python_code.py/
The -d flag lists only directories, and */ in the argument means everything with a slash / at the end.
4. Checking the File Type with find
We can use the find command to find files based on criteria. This command can filter files based on their extensions via the -name option:
$ find directory -name "*.js"
directory/ReactART.js
Note that we have to put the pattern in double quotes due to the asterisk. This pattern means everything that ends with .js.
We can also filter directories with the -type option:
$ find directory/* -type d
directory/images
directory/python_code.py
5. Checking the File Type with file
The file command will check the file type of files based on their contents:
$ file directory/handlers.py
directory/handlers.py: Python script, ASCII text executable
We can give a faux extension to this Python script, but the file command can see through it:
$ mv directory/handlers.py directory/handlers.zip
$ file directory/handlers.zip
directory/handlers.zip: Python script, ASCII text executable
The file command can accept more than one argument and a pattern:
$ file directory/handlers.py directory/hello-world.sh
directory/handlers.py: Python script, ASCII text executable
directory/hello-world.sh: Bourne-Again shell script, ASCII text executable
$ file directory/*py
directory/handlers.py: Python script, ASCII text executable
directory/python_code.py: directory
However, the file command isn’t perfect. Sometimes, it fails to guess the correct file type:
$ head directory/ReactART.js
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import * as React from 'react';
import ReactVersion from 'shared/ReactVersion';
import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
$ file directory/ReactART.js
directory/ReactART.js: C++ source, ASCII text
The file command failed to guess the file type of ReactART.js. It should be a JavaScript source, not a C++ source.
To filter files with the file command, we can combine it with the awk command and the grep command. Suppose we have a bunch of files and we want to check whether there are Python scripts or not. We can split the output of the file command with awk and grep commands:
$ file directory/* | awk -F':' '{print $2}' | awk '{$1=$1};1'
directory
Python script, ASCII text executable
Bourne-Again shell script, ASCII text executable
Bourne-Again shell script, ASCII text executable
directory
Zip archive data, at least v1.0 to extract
directory
C++ source, ASCII text
$ file directory/* | awk -F':' '{print $2}' | awk '{$1=$1};1' | grep "Python script"
Python script, ASCII text executable
The -F flag is to choose the separator character. The $2 in the string with curly braces is the second column of the separated output strings. The last awk command is to trim the leading spaces of the output.
Of course, we don’t have to use the awk command:
$ file directory/* | grep "Python script"
directory/handlers.py: Python script, ASCII text executable
We just have to make sure we don’t have files with “Python script” in their file names.
6. Checking the File Type with a Bash Script
Bash supports checking a file type in a directory. We can use the -e*, -d, and *-f flags in the if statements:
$ cat check-file-type.sh
#!/bin/bash
if [ -e directory/*.js ]; then
echo "There are JavaScript files or directories with .js extension inside 'directory'"
fi
if [ -d directory/ ]; then
echo "'directory' is a directory"
fi
if [ -f directory/*.js ]; then
echo "There are JavaScript files (not directories with .js extension) inside ‘directory’"
fi
$ ./check-file-type.sh
There are JavaScript files or directories with .js extension inside 'directory'
'directory' is a directory
There are JavaScript files (not directories with .js extension) inside 'directory'
The -e flag is to check whether the files or the directories exist or not. The -f flag is to check whether the ordinary files (not directories) exist or not. Finally, the -d flag is to check whether this is a directory or not. This flag cannot accept the wildcard argument.
7. Conclusion
In this article, we saw different ways to check a file type inside a directory. Some tools like ls and find use file names to check the file type. Another tool like file uses the content of the file to check the file type.
First, we used the ls command. Then, we utilized the find command. Next, we used the file command. Finally, we wrote a bash script using some of its built-in flags for checking for the existence of files and directories as well as checking their types.