Using Square Brackets in Bash: Part 1 - Printable Version +- Sick Gaming (https://www.sickgaming.net) +-- Forum: Computers (https://www.sickgaming.net/forum-86.html) +--- Forum: Linux, FreeBSD, and Unix types (https://www.sickgaming.net/forum-88.html) +--- Thread: Using Square Brackets in Bash: Part 1 (/thread-89464.html) |
Using Square Brackets in Bash: Part 1 - xSicKxBot - 03-26-2019 Using Square Brackets in Bash: Part 1 <div style="margin: 5px 5% 10px 5%;"><img src="http://www.sickgaming.net/blog/wp-content/uploads/2019/03/using-square-brackets-in-bash-part-1.jpg" width="1255" height="853" title="" alt="" /></div><div><div><img src="http://www.sickgaming.net/blog/wp-content/uploads/2019/03/using-square-brackets-in-bash-part-1.jpg" class="ff-og-image-inserted"></div> <p>After taking a look at <a href="https://www.linux.com/blog/learn/2019/2/all-about-curly-braces-bash">how curly braces (<code>{}</code>) work on the command line</a>, now it’s time to tackle brackets (<code>[]</code>) and see how they are used in different contexts.</p> <h3>Globbing</h3> <p>The first and easiest use of square brackets is in <em>globbing</em>. You have probably used globbing before without knowing it. Think of all the times you have listed files of a certain type, say, you wanted to list JPEGs, but not PNGs:</p> <pre> ls *.jpg</pre> <p>Using wildcards to get all the results that fit a certain pattern is precisely what we call globbing.</p> <p>In the example above, the asterisk means “<i>zero or more characters</i>“. There is another globbing wildcard, <code>?</code>, which means “<i>exactly one character</i>“, so, while</p> <pre> ls d*k* </pre> <p>will list files called <i>darkly</i> and <i>ducky</i> (and <i>dark</i> and <i>duck</i> — remember <code>*</code> can also be zero characters),</p> <pre> ls d*k? </pre> <p>will not list <i>darkly</i> (or <i>dark</i> or <i>duck</i>), but it will list <i>ducky</i>.</p> <p>Square brackets are used in globbing for sets of characters. To see what this means, make directory in which to carry out tests, <code>cd</code> into it and create a bunch of files like this:</p> <pre> touch file0{0..9}{0..9} </pre> <p>(If you don’t know why that works, <a href="https://www.linux.com/blog/learn/2019/2/all-about-curly-braces-bash">take a look at the last installment that explains curly braces <code>{}</code></a>).</p> <p>This will create files <i>file000</i>, <i>file001</i>, <i>file002</i>, etc., through <i>file097</i>, <i>file098</i> and <i>file099</i>.</p> <p>Then, to list the files in the 70s and 80s, you can do this:</p> <pre> ls file0[78]? </pre> <p>To list <i>file022</i>, <i>file027</i>, <i>file028</i>, <i>file052</i>, <i>file057</i>, <i>file058</i>, <i>file092</i>, <i>file097</i>, and <i>file98</i> you can do this:</p> <pre> ls file0[259][278] </pre> <p>Of course, you can use globbing (and square brackets for sets) for more than just <code>ls</code>. You can use globbing with any other tool for listing, removing, moving, or copying files, although the last two may require a bit of lateral thinking.</p> <p>Let’s say you want to create duplicates of files <i>file010</i> through <i>file029</i> and call the copies <i>archive010</i>, <i>archive011</i>, <i>archive012</i>, etc..</p> <p>You can’t do:</p> <pre> cp file0[12]? archive0[12]? </pre> <p>Because globbing is for matching against existing files and directories and the <i>archive…</i> files don’t exist yet.</p> <p>Doing this:</p> <pre> cp file0[12]? archive0[1..2][0..9] </pre> <p>won’t work either, because <code>cp</code> doesn’t let you copy many files to other many new files. Copying many files only works if you are copying them to a directory, so this:</p> <pre> mkdir archive cp file0[12]? archive </pre> <p>would work, but it would copy the files, using their same names, into a directory called <i>archive/</i>. This is not what you set out to do.</p> <p>However, if you look back at <a href="https://www.linux.com/blog/learn/2019/2/all-about-curly-braces-bash">the article on curly braces (<code>{}</code>)</a>, you will remember how you can use <code>%</code> to lop off the end of a string contained in a variable.</p> <p>Of course, there is a way you can also lop of the beginning of string contained in a variable. Instead of <code>%</code>, you use <code>#</code>.</p> <p>For practice, you can try this:</p> <pre> myvar="Hello World" echo Goodbye Cruel ${myvar#Hello} </pre> <p>It prints “<i>Goodbye Cruel World</i>” because <code>#Hello</code> gets rid of the <i>Hello</i> part at the beginning of the string stored in <code>myvar</code>.</p> <p>You can use this feature alongside your globbing tools to make your <i>archive</i> duplicates:</p> <pre> for i in file0[12]?;\ do\ cp $i archive${i#file};\ done </pre> <p>The first line tells the Bash interpreter that you want to loop through all the files that contain the string <i>file0</i> followed by the digits <i>1</i> or <i>2</i>, and then one other character, which can be anything. The second line <code>do</code> indicates that what follows is the instruction or list of instructions you want the interpreter to loop through.</p> <p>Line 3 is where the actually copying happens, and you use the contents of the loop variable <em><code>i</code></em><em> </em>twice: First, straight out, as the first parameter of the <code>cp</code> command, and then you add <i>archive</i> to its contents, while at the same time cutting of <i>file</i>. So, if <em><code>i</code></em> contains, say, <i>file019</i>…</p> <pre> "archive" + "file019" - "file" = "archive019" </pre> <p>the <code>cp</code> line is expanded to this:</p> <pre> cp file019 archive019 </pre> <p>Finally, notice how you can use the backslash <code>\</code> to split a chain of commands over several lines for clarity.</p> <p>In part two, we’ll look at more ways to use square brackets. Stay tuned.</p> </div> |