{"id":13199,"date":"2026-01-12T01:15:00","date_gmt":"2026-01-12T06:15:00","guid":{"rendered":"https:\/\/www.both.org\/?p=13199"},"modified":"2026-01-14T20:49:39","modified_gmt":"2026-01-15T01:49:39","slug":"using-wildcards-on-the-bash-command-line","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=13199","title":{"rendered":"Using Wildcards on the Bash Command Line"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"13199\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">1    <\/span>\r\n<\/div><\/div>\n<p>The function of any shell, whether Bash, KSH, CSH is to take commands entered on the command line; expand any file globs, that is wildcard characters * and ? and sets, into complete file or directory names; convert the result into tokens for use by the kernel; and then pass the resulting command to the kernel for execution. The shell then sends any resulting output from execution of the command to STDOUT.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u0007Special Pattern Characters<\/h2>\n\n\n\n<p>Although most SysAdmins talk about wildcards, or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Glob_(programming\" data-type=\"link\" data-id=\"https:\/\/en.wikipedia.org\/wiki\/Glob_(programming\" target=\"_blank\" rel=\"noreferrer noopener\">file globbing<\/a> as it&#8217;s also called, we really mean special pattern characters that allow us significant flexibility in matching file names and other strings when performing various actions. These special pattern characters allow matching single, multiple, or specific characters in a string.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>? <\/strong>    Matches only one of any character in the specified location within the string.<\/li>\n\n\n\n<li><strong>*<\/strong>     Zero or more of any character in the specified location within the string.<\/li>\n<\/ol>\n\n\n\n<p>In all likelihood you have used these before. Let\u2019s experiment with some ways we can use these more effectively.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preparation<\/h2>\n\n\n\n<p>But first, we need to create a directory in which to perform these experiments, and then we&#8217;ll create a lot of files. We&#8217;ll do this as a non-root user so there&#8217;s no danger of borking the operating system. We&#8217;ll also use a directory specifically for this in order to prevent the possibility of damaging files in your home directory. That&#8217;s not likely, but we should be safe.<\/p>\n\n\n\n<p>Start by creating a test directory in your home (~) directory, then make it the PWD. I&#8217;m going to be a little fancy here by using a variable for the name of the new directory.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>NewDir=\"testdir\" ; cd ; mkdir $NewDir ; cd $NewDir<\/strong>\ndboth@essex:~\/testdir$<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Brace Expansion<\/h3>\n\n\n\n<p>Now we need to create a large number of files so we&#8217;ll take a bit of a detour to do that. <\/p>\n\n\n\n<p>If you&#8217;re not familiar with brace expansion, it can be a powerful way to generate lists of arbitrary strings and insert them into a specific location within an enclosing static string, or at either end of a static string. First let\u2019s just see what a basic brace expansion does. Note the use of curly brace {} to enclose the components.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>echo {string1,string2,string3}<\/strong>\nstring1 string2 string3<\/code><\/pre>\n\n\n\n<p>Well, that is not very helpful, is it? But look what happens when we use it just a bit differently.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>echo \"Hello \"{David,Jen,Rikki,Jason}.<\/strong>\nHello David. Hello Jen. Hello Rikki. Hello Jason.<\/code><\/pre>\n\n\n\n<p>That looks like something we might be able to use because it can save a good deal of typing when we create our files. Now try this.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>echo b{ed,olt,ar}s<\/strong>\nbeds bolts bars<\/code><\/pre>\n\n\n\n<p>Here is one method for generating file names for testing.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>echo testfile{0,1,2,3,4,5,6,7,8,9}.txt<\/strong>\ntestfile0.txt testfile1.txt testfile2.txt testfile3.txt testfile4.txt testfile5.txt testfile6.txt testfile7.txt testfile8.txt testfile9.txt<\/code><\/pre>\n\n\n\n<p>And here is an even better method for creating sequentially numbered files.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>echo test{0..9}.file<\/strong>\ntest0.file test1.file test2.file test3.file test4.file test5.file test6.file test7.file test8.file test9.file<\/code><\/pre>\n\n\n\n<p>The {x..y} syntax, where x and y are integers, expands to be all integers between and including x and y.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the Files<\/h2>\n\n\n\n<p>Now we can create the files we need to explore wildcards.<\/p>\n\n\n\n<p>We want to create a files with a number of name components so that the have a greater variety to make more interesting examples. The files we create will all contain a small amount of data to make this a more realistic exercise.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>for Name in `echo {my,your,our}.test.file.{000..200}{a..f}.{txt,asc,file,text}` ; do echo \"This file is named $Name\" &gt; $Name ; done<\/strong><\/code><\/pre>\n\n\n\n<p>This command creates 14,472 files each of which has a text including it&#8217;s own file name as content. This consumes about 58M of total space in the directory. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Working with Wildcards &#8212; Finally!<\/h2>\n\n\n\n<p>How did I know that the command above would create 14,472 files? Well, I didn&#8217;t. I just ran the little command line program to create them and then the following program to count the number of files in the test directory. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>ll | wc -l<\/strong>\n14473<\/code><\/pre>\n\n\n\n<p>In order to achieve this result we must understand the structure of the filenames we created. They all contain the string \u201ctest\u201d so we can use that. The command uses the shell\u2019s built-in file globbing to match all files that contain the string \u201ctest\u201d anywhere in their names, and that can have any number of any character both before and after that one specific string. Let\u2019s just see what that looks like without counting the number of lines in the output.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dboth@essex:~\/testdir$ <strong>ls *test*<\/strong><\/code><\/pre>\n\n\n\n<p>I am sure that \u201cyou\u201d don\u2019t want any of \u201cmy\u201d files in &#8220;your&#8221; home directory. First see how many files that begin with \u201cmy\u201d there are, then delete them all and verify that none are left.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls my* | wc -l<\/strong>\n4824\n$ <strong>rm -v my* ; ls my*<\/strong><\/code><\/pre>\n\n\n\n<p>The -v option of the <strong>rm<\/strong> command lists every file as it deletes it. This information could be redirected to a log file for keeping a record of what was done. This file glob enables the <strong>ls<\/strong> command to list every file that starts with \u201cmy\u201d and perform actions on them.<\/p>\n\n\n\n<p>Find all of \u201cour\u201d files that have txt as the ending extension.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls our*txt | wc -l<\/strong>\n1206<\/code><\/pre>\n\n\n\n<p>Let&#8217;s list all files that contain 6 in the tens position of the three digit number embedded in the file names, and that end with asc.<\/p>\n\n\n\n<p>We must do this with a little extra work to ensure that we specify the positioning of the \u201c6\u201d carefully to prevent listing all of the files that only contain a 6 in the hundreds or ones position but not in the tens position of the three digit number. We know that none of the file names contains 6 in the hundreds position, but this makes our glob a bit more general so that it would work in both of those cases.<\/p>\n\n\n\n<p>We don&#8217;t care whether the file name starts with our or your, but we use the final \u201ce.\u201d of \u201cfile.\u201d \u2013 with the dot \u2013 to anchor the next three characters. After \u201ce.\u201d in the file name, all of the files have three digits. We do not care about the first and third digits, just the second one. So we use the ? to explicitly define that we have one and only one character before and after the 6. We than use the * to specify that we don&#8217;t care how many or which characters we have after that but that we do want to list files that end with \u201casc\u201d.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls *e.?6?*.asc<\/strong><\/code><\/pre>\n\n\n\n<p>How many files that match that specification?<\/p>\n\n\n\n<p>Let\u2019s look at all files that have a 6 in the middle position of the three digit number, but which also has an \u201ca\u201d after the number, as in x6xa. We want all files that match this pattern regardless of the trailing extension, asc, txt, text, or file.<\/p>\n\n\n\n<p>The file pattern specification we have now is almost where we need it in order to do this. <\/p>\n\n\n\n<pre class=\"wp-block-code has-medium-font-size\"><code>$ <strong>ls *e.?6?a.*<\/strong>\nour.test.file.060a.asc   our.test.file.160a.asc   your.test.file.060a.asc   your.test.file.160a.asc\nour.test.file.060a.file  our.test.file.160a.file  your.test.file.060a.file  your.test.file.160a.file\nour.test.file.060a.text  our.test.file.160a.text  your.test.file.060a.text  your.test.file.160a.text\nour.test.file.060a.txt   our.test.file.160a.txt   your.test.file.060a.txt   your.test.file.160a.txt\nour.test.file.061a.asc   our.test.file.161a.asc   your.test.file.061a.asc   your.test.file.161a.asc\nour.test.file.061a.file  our.test.file.161a.file  your.test.file.061a.file  your.test.file.161a.file\nour.test.file.061a.text  our.test.file.161a.text  your.test.file.061a.text  your.test.file.161a.text\n&lt;SNIP&gt;\nour.test.file.068a.txt   our.test.file.168a.txt   your.test.file.068a.txt   your.test.file.168a.txt\nour.test.file.069a.asc   our.test.file.169a.asc   your.test.file.069a.asc   your.test.file.169a.asc\nour.test.file.069a.file  our.test.file.169a.file  your.test.file.069a.file  your.test.file.169a.file\nour.test.file.069a.text  our.test.file.169a.text  your.test.file.069a.text  your.test.file.169a.text\nour.test.file.069a.txt   our.test.file.169a.txt   your.test.file.069a.txt   your.test.file.169a.txt<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using Sets<\/h2>\n\n\n\n<p>Sets are an interesting and powerful form of special pattern characters. They provide a means to specify that a particular one-character location in a string contains any character from the list inside the square braces []. Sets can be used alone or in conjunction with other special pattern characters.<\/p>\n\n\n\n<p>A set can consist of one or more characters that will be compared against the characters in a specific, single position in the string for a match. The following list shows some typical example sets and the string characters they match.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[0-9] Any numerical character.<\/li>\n\n\n\n<li>[a-z] Lowercase alpha.<\/li>\n\n\n\n<li>[A-Z] Uppercase alpha.<\/li>\n\n\n\n<li>[a-zA-Z] Any uppercase or lowercase alpha.<\/li>\n\n\n\n<li>[abc] The three lowercase alpha characters, a,b, and c.<\/li>\n\n\n\n<li>[!a-z] Any characters except for lowercase alpha.<\/li>\n\n\n\n<li>[!5-7] Any numeric characters except 5, 6, or 7.<\/li>\n\n\n\n<li>[a-gxz] Lowercase a through g, x, and z.<\/li>\n\n\n\n<li>[A-F0-9] Uppercase A through F, or any numeric.<\/li>\n<\/ul>\n\n\n\n<p>Once again, this will be easier to explain if we just go right to the experiment.<\/p>\n\n\n\n<p>The PWD should still be ~\/testdir. Start by finding the files that contain a 6 in the center of the three digit number in the file name.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls *&#91;0-9]6&#91;0-9]*<\/strong><\/code><\/pre>\n\n\n\n<p>We could use this alternate pattern because we know that the leftmost digit must be 0 or 1. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls *&#91;01]6&#91;0-9]*<\/strong><\/code><\/pre>\n\n\n\n<p>Count the number of file names returned for both cases to verify this.<\/p>\n\n\n\n<p>Now let\u2019s look for the file names that contain a 6 in only the center position, but not in either of the other two digits. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls *\\.&#91;!6]6&#91;!6]*<\/strong><\/code><\/pre>\n\n\n\n<p>We need to anchor this expression to the period that begins the three digits, otherwise the results will not be what we want. Think about what the result would be, then try it without that anchor to verify.<\/p>\n\n\n\n<p>Find the files that match the pattern we have so far but which also end in t.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls *\\.&#91;!6]6&#91;!6]*t<\/strong><\/code><\/pre>\n\n\n\n<p>Now find all of the files that match the pattern above but which also have \u201ca\u201d or \u201ce\u201d immediately following the number.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls *\\.&#91;!6]6&#91;!6]&#91;ae]*t<\/strong><\/code><\/pre>\n\n\n\n<p>These are just a few examples of using sets. Continue to experiment with them to enhance your understanding.<\/p>\n\n\n\n<p>Sets provide a powerful extension to pattern matching that gives us even more flexibility in searching for files. It is important to remember, however, that the primary use of these tools is not merely to \u201cfind\u201d these files so we can look at their names. It is to locate files that match a pattern so that we can perform some operation on them, such as deleting, moving, adding text to them, searching their contents for specific character strings, and more.<\/p>\n\n\n\n<p>When you&#8217;ve finished experimenting, you can delete the testdir directory and it&#8217;s contents.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thoughts<\/h2>\n\n\n\n<p>Special pattern characters, AKA wildcards or fileglobs,  allow us an amazing amount of flexibility in matching file names and other strings when performing various actions on our Linux computers. I use them daily and would be hard pressed to do the things I need to do without them.<\/p>\n\n\n\n<p>A few file managers have a decent search that can use these same wildcard expressions, one of which is Xfe, the default for the Xfce desktop. But it still takes longer to do the search, and using the resulting list of files is significantly restrictive compared to the capabilities we have on the command line.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>1 The function of any shell, whether Bash, KSH, CSH is to take commands entered on the command<\/p>\n","protected":false},"author":2,"featured_media":13344,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[149,100,5],"tags":[151,910,104,384,912,911],"class_list":["post-13199","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bash","category-command-line","category-linux","tag-bash","tag-brace-expansion","tag-command-line","tag-file-globbing","tag-special-pattern-characters","tag-wildcards"],"modified_by":"David Both","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/13199","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=13199"}],"version-history":[{"count":39,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/13199\/revisions"}],"predecessor-version":[{"id":13248,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/13199\/revisions\/13248"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/13344"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=13199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=13199"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=13199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}