Find file names that don't contain a specified string


find . ! -name '*2013*'

Add a ! -type d to also exclude the files of type directory (like . itself), or -type f to include only regular files, excluding all other types of files (directories, fifos, symlinks, devices, sockets...).

Beware however that * matches a sequence of 0 or more characters. So it could report file names that contain 2013 if that 2013 was preceded or followed by something that cannot be fully decoded as valid characters in the current locale.

That can happen if you're in a locale where the characters can be encoded on more than one byte (like in UTF-8) for file names that are encoded in a different encoding. For instance, in a UTF-8 locale, it would report a Stéphane2013 file if that é had been encoded in the iso8859-15 character set (as the 0xe9 byte).

Best would be to make sure the file names are encoded in the locale's character set, but if you can't guarantee it, a work around is to run find in the C locale:

LC_ALL=C find . ! -name '*2013*'

Ksh filename patterns are sufficient:

# files with 2013
ls -d -- *2013*

# files without 2013
ls -d -- !(*2013*)


If your shell is bash, you need to run shopt -s extglob before you can use this pattern (you can put it in your .bashrc). If your shell is zsh, you need to run setopt ksh_glob (you can put it in your .zshrc). Zsh also offers ls -d -- ^*2013*, which requires a preliminary setopt extended_glob.

Depending on what you're doing with these filenames, ls may not be the right command to use. To store them in an array

filenames=( !(*2013*) )
for f in "${filenames[@]}"; do ...; done