20

I want to list all files in a directory that start with 'abc' and end with '.zip'

I'm trying to use ls.

The directory has a lot of zip files starting with abc<date> and xvz<date>. I only want to get the list of the abc<date>.zip

Anthon
  • 79,293
unix_dude
  • 231

5 Answers5

24

ls doesn't do pattern matching on file names. It just lists the content of the directories and the files it is being given as arguments.

Your shell on the other hand has a feature called globbing or filename generation that expands a pattern into a list of files matching that pattern.

Here that glob pattern would be abc*.zip (* being a wildcard that stands for any number of characters).

You'd pass it to any command you like such as printf for printing:

printf '%s\n' abc*.zip

You could also pass it to ls -l to display the attributes of those files:

ls -ld abc*.zip

(we need -d because if any of those files are of type directory, ls would list their content otherwise).

Or to unzip to extract them if only unzip could extract more than one file at a time. Unfortunately it doesn't, so you'd need either to use xargs -n1 or a for loop:

printf '%s\0' abc*.zip | xargs -r0n1 unzip

Or:

for file in abc*.zip; do unzip "$file"; done

But in fact, unzip being more like a port of a MS-DOS command, unzip itself would treat its argument as a glob. In other words, unzip 'abc*.zip' will not unzip the file called abc*.zip (a perfectly valid file name on Unix, not on Microsoft operating systems), but the files matching the abc*.zip pattern, so you'd actually want:

 unzip 'abc*.zip'

(Actually our xargs and for approach above would be wrong, because if there's a file called abc*.zip for instance, unzip would treat it as a pattern! See bsdtar for a more unixy way to extract zip archives)


For case insensitive matching, you'd use [aA][bB][cC]*.[zZ][iI][pP] portably. Some shells have extended globbing operators for case insensitive matching:

  • zsh:

    setopt extendedglob
    ls -ld (#i)abc*.zip
    

    Or:

    ls -ld ((#i)abc)*.zip
    

    if you only want the abc part to be case insensitive.

  • ksh93:

    ls -ld ~(i)abc*.zip
    

    or:

    ls -ld ~(i:abc)*.zip
    
  • with bash.

    shopt -s nocaseglob
    ls -ld abc*.zip
    

    (no way to have only parts of the globs case sensitive there other than by using the portable syntax).

  • with yash:

    set +o case-glob
    ls -ld abc*.zip
    

    same remark as for bash above.

  • In bash ls -ld l*.so gives me ls: cannot access 'l*.so': No such file or directory. Am I missing something? – Ofek Shilon Jun 08 '22 at 17:24
  • @OfekShilon, you'd need to run that from within a directory that has at least one entry whose name starts with l and ends in .so (and the noglob option of your shell, assuming it's POSIX-like not to be enabled). – Stéphane Chazelas Jun 08 '22 at 17:58
17
ls abc*.zip

This however will fail if there are too many files (there is a limit to shell expansion in term of how many arguments it can expand to).

find . -name "abc*.zip"

This is probably the most universal. The quotes must be there. With some find implementations, you can also use -iname instead of -name for case insensitive search (aBc<date>.ZIP would also match).

ls | grep -x "abc.*\.zip"

Mind the .* and \. since the filter grep uses is regex which is different from the wildcard notation the shell uses for expansion. Use grep -i for case insensitive search.

Jan Dusek
  • 401
  • 1
    Note that that limit is not a shell limit. It's a kernel limit in the execve() system call. – Stéphane Chazelas Apr 19 '16 at 13:25
  • It should probably be noted that find will look for those files in subdirectories as well. Use find . ! -name . -prune -name 'abc*.zip' -print or find . -maxdepth 1 -name 'abc*.zip' if your find supports -maxdepth like on GNU or BSD or find . -depth 1 -name 'abc*.zip' if your find supports a -depth <n> like on some BSDs to restrict to the current directory. – Stéphane Chazelas Apr 19 '16 at 13:28
  • $ ls ../*.a worked for me (list archives in parent dir). – Daniel Jan 24 '18 at 16:38
1

You can pipe the output of ls to grep.

Let's say I want to find all files that contain abc in the filename

ls -f | grep abc

If you need specific variations of patterns, man grep

0

Try using ls abc*.zip to narrow down the results to those matching your criteria for a starting string of abc and an ending of .zip The asterisk will expand to match those results without including xvz starting characters.

Jeff
  • 920
-1

You must specified the directory where ls will search in an example

ls -la ~/file*.* 
ls -la ./file*.*

it works for me, but obviously it doesn't support searching by pattern