I'm unable to show JUST ONE file from the output of ls using bash extended globbing.

From info bash

  If the `extglob' shell option is enabled using the `shopt' builtin,
several extended pattern matching operators are recognized.  In the
following description, a PATTERN-LIST is a list of one or more patterns
separated by a `|'.  Composite patterns may be formed using one or more
of the following sub-patterns:

     Matches zero or one occurrence of the given patterns.

     Matches zero or more occurrences of the given patterns.

     Matches one or more occurrences of the given patterns.

     Matches exactly one of the given patterns.

     Matches anything except one of the given patterns.


shops -s extglob

ls -l /boot/@(vmlinuz*)
-rw-r--r--  1 root root 1829516 Apr 21  2009 /boot/vmlinuz-2.6.9-89.EL
-rw-r--r--  1 root root 1700492 Apr 21  2009 /boot/vmlinuz-2.6.9-89.ELsmp

ls -l /boot/?(vmlinuz*)
-rw-r--r--  1 root root 1829516 Apr 21  2009 /boot/vmlinuz-2.6.9-89.EL
-rw-r--r--  1 root root 1700492 Apr 21  2009 /boot/vmlinuz-2.6.9-89.ELsmp

How do I show only ONE file?

  • 1
    What are you trying to achieve? This sounds like an X-Y problem... – jasonwryan Nov 19 '14 at 2:46
  • 2
    "occurrence" in this context means occurrence of the pattern in a single filename not occurrence in the directory of filenames matching the pattern – steeldriver Nov 19 '14 at 2:50
up vote 2 down vote accepted

Bash has no feature to expand just one match out of many.

The pattern @(foo) matches just one occurrence of the pattern foo. That is, it matches foo, but not foofoo. This syntactic form is useful to build or patterns like @(foo|bar), which matches either foo or bar. It can be used as part of longer patterns like @(foo|bar)-*.txt, which matches foo-hello.txt, foo-42.txt, bar-42.txt, etc.

If you want to use one match among many, you can put the matches in an array, and then use an element of the array.

ls -l "${kernels[0]}"

Matches are always sorted in lexicographic order, so this will print the first match in lexicographic order.

Note that if the pattern doesn't match any file, you'll get an array containing a single element which is the unchanged pattern:

$ a=(doesnotmatchanything*)
$ ls -l "${a[0]}"
ls: cannot access doesnotmatchanything*: No such file or directory

Set the nullglob option to get an empty array instead.

shopt -s nullglob
if ((${#kernels[@]} == 0)); then
  echo "No kernels here"
  echo "One of the ${#kernels[@]} kernels is ${kernels[0]}"

Zsh has convenient features here. The glob qualifier [NUM] causes the pattern to expand to only the NUMth match; the variant [NUM1,NUM2] expands to the NUM1th through NUM2th matches (starting at 1).

% ls -l vmlinuz*([1])
lrwxrwxrwx 1 root root 26 Nov 15 21:12 vmlinuz -> vmlinuz-3.16-0.bpo.3-amd64
% ls -l nosuchfilehere*([1])
zsh: no matches found: nosuchfilehere*([1])

The glob qualifier N causes the pattern to expand to an empty list if no file is matched.

if ((#kernels)); then
  ls -l $kernels
  echo "No kernels here"

The glob qualifier om sorts matches by increasing age instead of by name (m is for modification time); Om sorts by decreasing age . So vmlinuz*(om[1]) expands to the most recent kernel file.

"one match" doesn't mean what you think it does. It means one match within the pattern, not to only return one file. ls doesn't have any options like that. Normally, people do things like ls |head -1 or similar.

  • 2
    +1 An example of the proper use of @ would be @(foo|bar).txt to match foo.txt or bar.txt but not any other file. – chepner Nov 19 '14 at 4:09
  • What I want to achieve is to return just one result from the vmlinuz* glob. Can this be achieved in Bash, without external tools? – Felipe Alvarez Nov 19 '14 at 6:32

Your Answer


By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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