{"id":91411,"date":"2019-04-02T14:00:00","date_gmt":"2019-04-02T14:00:00","guid":{"rendered":"http:\/\/www.sickgaming.net\/blog\/2019\/04\/02\/using-square-brackets-in-bash-part-2\/"},"modified":"2019-04-02T14:00:00","modified_gmt":"2019-04-02T14:00:00","slug":"using-square-brackets-in-bash-part-2","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2019\/04\/02\/using-square-brackets-in-bash-part-2\/","title":{"rendered":"Using Square Brackets in Bash: Part 2"},"content":{"rendered":"<div><img decoding=\"async\" src=\"http:\/\/www.sickgaming.net\/blog\/wp-content\/uploads\/2019\/04\/using-square-brackets-in-bash-part-2.jpg\" class=\"ff-og-image-inserted\"><\/div>\n<p>Welcome back to our mini-series on square brackets. In the <a href=\"https:\/\/www.linux.com\/blog\/2019\/3\/using-square-brackets-bash-part-1\">previous article<\/a>, we looked at various ways square brackets are used at the command line, including globbing. If you&#8217;ve not read that article, you might want to start there.<\/p>\n<p>Square brackets can also be used as a command. Yep, for example, in:<\/p>\n<pre>\n[ \"a\" = \"a\" ]\n<\/pre>\n<p>which is, by the way, a valid command that you can execute,&nbsp;<code>[ ... ]<\/code> is a command. Notice that there are spaces between the opening bracket <code>[<\/code> and the parameters <code>\"a\" = \"a\"<\/code>, and then between the parameters and the closing bracket <code>]<\/code>. That is precisely because the brackets here act as a command, and you are separating the command from its parameters.<\/p>\n<p>You would read the above line as &#8220;<i>test whether the string &#8220;a&#8221; is the same as string &#8220;a&#8221;<\/i>&#8220;. If the premise is true, the <code>[ ... ]<\/code> command finishes with an exit status of 0. If not, the exit status is 1. <a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/2\/logical-ampersand-bash\">We talked about exit statuses in a previous article<\/a>, and there you saw that you could access the value by checking the <code>$?<\/code> variable.<\/p>\n<p>Try it out:<\/p>\n<pre>\n[ \"a\" = \"a\" ]\necho $?\n<\/pre>\n<p>And now try:<\/p>\n<pre>\n[ \"a\" = \"b\" ]\necho $?\n<\/pre>\n<p>In the first case, you will get a 0 (the premise is true), and running the second will give you a 1 (the premise is false). Remember that, in Bash, an exit status from a command that is 0 means it exited normally&nbsp;with no errors, and that makes it <code>true<\/code>. If there were any errors, the exit value would be a non-zero value (<code>false<\/code>). The <code>[ ... ]<\/code> command follows the same rules so that it is consistent with the rest of the other commands.<\/p>\n<p>The <code>[ ... ]<\/code> command comes in handy in <code>if ... then<\/code> constructs and also in loops that require a certain condition to be met (or not) before exiting, like the <code>while<\/code> and <code>until<\/code> loops.<\/p>\n<p>The logical operators for testing stuff are pretty straightforward:<\/p>\n<pre>\n<b>[ STRING1 = STRING2 ]<\/b> =&gt; checks to see if the strings are equal\n<b>[ STRING1 != STRING2 ]<\/b> =&gt; checks to see if the strings are not equal <b>[ INTEGER1 -eq INTEGER2 ]<\/b> =&gt; checks to see if INTEGER1 is equal to INTEGER2 <b>[ INTEGER1 -ge INTEGER2 ]<\/b> =&gt; checks to see if INTEGER1 is greater than or equal to INTEGER2\n<b>[ INTEGER1 -gt INTEGER2 ]<\/b> =&gt; checks to see if INTEGER1 is greater than INTEGER2\n<b>[ INTEGER1 -le INTEGER2 ]<\/b> =&gt; checks to see if INTEGER1 is less than or equal to INTEGER2\n<b>[ INTEGER1 -lt INTEGER2 ]<\/b> =&gt; checks to see if INTEGER1 is less than INTEGER2\n<b>[ INTEGER1 -ne INTEGER2 ]<\/b> =&gt; checks to see if INTEGER1 is not equal to INTEGER2\netc...\n<\/pre>\n<p>You can also test for some very shell-specific things. The <code>-f<\/code> option, for example, tests whether a file exists or not:<\/p>\n<pre>\nfor i in {000..099}; \\ do \\ if [ -f file$i ]; \\ then \\ echo file$i exists; \\ else \\ touch file$i; \\ echo I made file$i; \\ fi; \\\ndone\n<\/pre>\n<p>If you run&nbsp;this in your test directory, line 3 will test to whether a file is in your long list of files. If it does exist, it will just print a message; but if it doesn&#8217;t exist, it will create it, to make sure the whole set is complete.<\/p>\n<p>You could write the loop more compactly like this:<\/p>\n<pre>\nfor i in {000..099};\\\ndo\\ if [ ! -f file$i ];\\ then\\ touch file$i;\\ echo I made file$i;\\ fi;\\\ndone\n<\/pre>\n<p>The <code>!<\/code> modifier in the condition inverts the premise, thus line 3 would translate to &#8220;<i>if the file <code>file$i<\/code> does not exist<\/i>&#8220;.<\/p>\n<p>Try it: delete some random files from the bunch you have in your test directory. Then run the loop shown above and watch how it rebuilds the list.<\/p>\n<p>There are plenty of other tests you can try, including&nbsp;<code>-d<\/code> tests to see if the name belongs to a directory and <code>-h<\/code> tests to see if it is a symbolic link. You can also test whether a files belongs to a certain group of users (<code>-G<\/code>), whether one file is older than another (<code>-ot<\/code>), or even whether a file contains something or is, on the other hand, empty.<\/p>\n<p>Try the following for example. Add some content to some of your files:<\/p>\n<pre>\necho \"Hello World\" &gt;&gt; file023\necho \"This is a message\" &gt;&gt; file065\necho \"To humanity\" &gt;&gt; file010\n<\/pre>\n<p>and then run this:<\/p>\n<pre>\nfor i in {000..099};\\\ndo\\ if [ ! -s file$i ];\\ then\\ rm file$i;\\ echo I removed file$i;\\ fi;\\\ndone\n<\/pre>\n<p>And you&#8217;ll remove all the files that are empty, leaving only the ones you added content to.<\/p>\n<p>To find out more, check the manual page for the <code>test<\/code> command (a synonym for <code>[ ... ]<\/code>) with <code>man test<\/code>.<\/p>\n<p>You may also see double brackets (<code>[[ ... ]]<\/code>) sometimes used in a similar way to single brackets. The reason for this is because double brackets give you a wider range of comparison operators. You can use <code>==<\/code>, for example, to compare a string to a pattern instead of just another string; or &lt; and <code>&gt;<\/code> to test whether a string would come before or after another in a dictionary.<\/p>\n<p>To find out more about extended operators <a href=\"https:\/\/www.gnu.org\/software\/bash\/manual\/bashref.html#Bash-Conditional-Expressions\">check out this full list of Bash expressions<\/a>.<\/p>\n<h3>Next Time<\/h3>\n<p>In an upcoming article, we&#8217;ll continue our tour and take a look at the role of parentheses <code>()<\/code> in Linux command lines. See you then!<\/p>\n<p><em>Read more:<\/em><\/p>\n<ol>\n<li><a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/1\/linux-tools-meaning-dot\">The Meaning of Dot (<code>.<\/code>)<\/a><\/li>\n<li><a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/1\/understanding-angle-brackets-bash\">Understanding Angle Brackets in Bash (<code>&lt;...&gt;<\/code>)<\/a><\/li>\n<li><a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/1\/more-about-angle-brackets-bash\">More About Angle Brackets in Bash(<code>&lt;<\/code> and <code>&gt;<\/code>)<\/a><\/li>\n<li><a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/2\/and-ampersand-and-linux\">And, Ampersand, and &amp; in Linux (<code>&amp;<\/code>)<\/a><\/li>\n<li><a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/2\/ampersands-and-file-descriptors-bash\">Ampersands and File Descriptors in Bash (<code>&amp;<\/code>)<\/a><\/li>\n<li><a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/2\/logical-ampersand-bash\">Logical &amp; in Bash (<code>&amp;<\/code>)<\/a><\/li>\n<li><a href=\"https:\/\/www.linux.com\/blog\/learn\/2019\/2\/all-about-curly-braces-bash\">All about {Curly Braces} in Bash (<code>{}<\/code>)<\/a><\/li>\n<li><a href=\"https:\/\/www.linux.com\/blog\/2019\/3\/using-square-brackets-bash-part-1\">Using Square Brackets in Bash: Part 1<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Welcome back to our mini-series on square brackets. In the previous article, we looked at various ways square brackets are used at the command line, including globbing. If you&#8217;ve not read that article, you might want to start there. Square brackets can also be used as a command. Yep, for example, in: [ &#8220;a&#8221; = [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":91412,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40],"tags":[],"class_list":["post-91411","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux-freebsd-unix"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/91411","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=91411"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/91411\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media\/91412"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=91411"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=91411"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=91411"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}