Skip to content

Commit

Permalink
Command Substitution + improved content linking.
Browse files Browse the repository at this point in the history
  • Loading branch information
lhunath committed Jan 27, 2017
1 parent e5be303 commit 0bc2c46
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 17 deletions.
12 changes: 6 additions & 6 deletions 02.commands.html
Expand Up @@ -175,7 +175,7 @@ <h2>The basic grammar of a bash command</h2>
<pre class="syntax">
[ <var>var</var><strong>=</strong><var>value</var> ... ] <var>name</var> [ <var>arg</var> ... ] [ <var>redirection</var> ... ]

<samp><u title="name">echo</u> <u title="arg #1">"Hello world!"</u></samp>
<samp><u title="name">echo</u> <u title="arg #1">"Hello world."</u></samp>
<samp><u title="var #1">IFS=,</u> <u title="name">read</u> <u title="arg #1">-a</u> <u title="arg #2">fields</u> <u title="redirection #1">&lt; file</u></samp>
</pre>

Expand Down Expand Up @@ -395,15 +395,15 @@ <h4>PATH.4. Create a script in your home directory, add it to your <var>PATH</va
<pre lang="bash" class="exercise"><samp>$ <kbd>ex</kbd><em>You can substitute your favorite editor here.</em>
: <kbd>i</kbd>
<kbd>#!/usr/bin/env bash
echo "Hello world!"
echo "Hello world."
.</kbd>
: <kbd>w myscript</kbd>
"myscript" [New] 2L, 40C written
: <kbd>q</kbd>
<span class="prompt">$ </span><kbd>chmod +x myscript</kbd>
<span class="prompt">$ </span><kbd>PATH=$PATH:~</kbd>
<span class="prompt">$ </span><kbd>myscript</kbd>
Hello world!</samp></pre>
Hello world.</samp></pre>

<h2>Command arguments and quoting literals</h2>

Expand Down Expand Up @@ -841,9 +841,9 @@ <h4>REDIR.5. Append the last command's standard output and error messages to the
ls: /bob/bash: No such file or directory
/bin/bash*</samp></pre>

<h4>REDIR.6. Use a here-string to show the string <kbd>Hello world!</kbd> on the terminal.</h4>
<pre lang="bash" class="exercise"><samp>$ <kbd>cat &lt;&lt;&lt; 'Hello world!'</kbd>
Hello world!</samp></pre>
<h4>REDIR.6. Use a here-string to show the string <kbd>Hello world.</kbd> on the terminal.</h4>
<pre lang="bash" class="exercise"><samp>$ <kbd>cat &lt;&lt;&lt; 'Hello world.'</kbd>
Hello world.</samp></pre>

<h4>REDIR.7. Fix this command so that the message is properly saved into the <code>log</code> file and such that FD 3 is properly closed afterwards: <kbd>exec 3&gt;&amp;2 2&gt;log; echo 'Hello!'; exec 2&gt;&amp;3</kbd></h4>
<pre lang="bash" class="exercise"><samp>$ <kbd>exec 3&gt;&amp;1 &gt;log; echo 'Hello!'; exec 1&gt;&amp;3 3&gt;&amp;-</kbd></samp></pre>
Expand Down
52 changes: 48 additions & 4 deletions 03.variables.html
Expand Up @@ -212,7 +212,7 @@ <h2>Tilde Expansion</h2>
<p>There is a different kind of expansion which we have been silently using in this guide without explicitly explaining it. It's called the <dfn>Tilde Expansion</dfn> and it involves replacing a tilde (<code>~</code>) in a pathname with the path to the current user's home directory:</p>

<pre lang="bash">
<span class="prompt">$ </span><kbd>echo 'I live in: ' ~</kbd><em>Note that expansions must not be quoted or they will become literal!</em>
<span class="prompt">$ </span><kbd>echo 'I live in: ' ~</kbd><em>Note that expansions must not be quoted or they will become <strong>literal</strong>!</em>
I live in: /Users/lhunath
</pre>

Expand All @@ -225,6 +225,43 @@ <h2>Tilde Expansion</h2>
My boss lives in: /var/root
</pre>

<h2>Command Substitution</h2>

<p>We now have a pretty good idea of what <dfn>expansion</dfn> means: we replace a syntactical token in our command by the situationally-specific equivalent value of that token. Thus far, we've only expanded pathnames, either as the result of a pathname expansion pattern or a tilde expansion operation.</p>

<p>But expansion can be used for so much more. We can use expansion to expand almost any kind of data into our command's arguments. <dfn>Command Substitution</dfn> is an extremely popular method of expanding data into command arguments. With <dfn>Command Substitution</dfn>, we effectively write a command within a command, and we ask bash to expand the inner command into its <em>output</em> and use that output as argument data for the main command:</p>

<pre lang="bash">
<span class="prompt">$ </span><kbd>echo 'Hello world.' &gt; hello.txt</kbd>
<span class="prompt">$ </span><kbd>cat hello.txt</kbd>
Hello world.
<span class="prompt">$ </span><kbd>echo "The file &lt;hello.txt&gt; contains: <mark>$(cat hello.txt)</mark>"</kbd>
The file &lt;hello.txt&gt; contains: <mark>Hello world.</mark>
</pre>

<p>What have we done here?<br>
We start out pretty simple: we create a file called <code>hello.txt</code> and put the string <code>Hello world.</code> into it. We then use the <code>cat</code> command to output the contents of the file. We can see the file contains the string we saved into it.</p>
<p>But then things get interesting: what we want to do here is output a message to the user that explains in a nice sentence what the string in our file is. To do this, we want to make the file's contents a "part of"
the sentence that we <code>echo</code> out. However, while we write the code for this sentence, there is no telling what the contents of the file is, so how can we type out the correct sentence in our script? The answer is expansion: We know how to get the contents of a file using <code>cat</code>, so here we <em>expand</em> the output of the <code>cat</code> command <em>into</em> our <code>echo</code> sentence. Bash will first run <code>cat hello.txt</code>, take the output of this command
(which is our string <code>Hello world.</code>) and then expand our <dfn>Command Substitution</dfn> syntax (the <code>$(cat ...)</code> part) into that output. Only after this expansion, bash will try to run the <code>echo</code> command. And can you guess what the argument to the <code>echo</code> command has become after our <dfn>Command Substitution</dfn> has expanded in-place? The answer is:<br>
<code>echo "The file &lt;hello.txt&gt; contains: Hello world."</code></p>

<p>This is the very first kind of value expansion that we've learned about. Value expansions allow us to expand data into command arguments. They are extremely useful and you will use them all the time. Bash has a fairly consistent syntax with regards to value expansions: they all start with a <code>$</code> symbol.</p>

<p><dfn>Command Substitution</dfn> essentially expands the <em>value of a command that was executed in a subshell</em>. As such, the syntax is a combination of the value-expansion prefix <code>$</code> followed by the subshell to expand: <code>(...)</code>. A subshell is essentially a small new bash process that is used to run a command while the main bash shell waits for the result. We'll learn more about subshells in a future chapter. Suffice it to say that the syntax for
expansions in bash is very consistent and very deliberate, which certainly helps with learning it!</p>

<aside class="rule">
<p>Very observant readers might have noticed that this guide tends to use single quotes to quote its strings but in this latest example switched to double quotes for the sentence that contained the expansion syntax. This is intentional: all value expansions (ie. all syntax with a <code>$</code> prefix) can only expand inside quoted arguments if the argument was <em>double-quoted</em>. Single quotes will turn the dollar-syntax into literal characters, causing bash to output the
dollar rather than expand its value in-place! It is thus important to double-quote all our arguments that contain value expansions.</p>
<p>
<q>Value expansions (<code>$...</code>) must <strong>always</strong> be double-quoted.</q>
</p>
</aside>
<aside class="warn">
<p>Never leave a value expansion unquoted. If you do, bash will tear the value apart using word-splitting, delete all whitespace from it and perform hidden pathname expansion on all the words in it!</p>
</aside>

</section>

<section>
Expand Down Expand Up @@ -277,15 +314,22 @@ <h3>Assignment</h3>
<span class="prompt">$ </span><kbd>item=' 4. Milk'</kbd><em>Use quotes to make the spaces literal.</em>
</pre>

<p>We can even combine this assignment syntax with other value expansions:</p>

<pre lang="bash">
<span class="prompt">$ </span><kbd>contents="$(cat hello.txt)"</kbd>
</pre>

<p>Here, we perform a <dfn>Command Substitution</dfn>, expanding the contents of the <code>hello.txt</code> file into our assignment syntax, which subsequently results in that contents getting assigned to the <var>contents</var> variable.</p>

<h3>Parameter Expansion</h3>

<p>Assigning values to variables is neat but not really immediately useful. It's being able to re-use those values at any time that makes parameters so interesting. Re-using parameter values is done by expanding them. <dfn>Parameter Expansion</dfn> effectively takes the data out of your parameter and inlines it into the data of your command. As we saw briefly before, we expand parameters by prefixing their name with a <code>$</code> symbol. Whenever you see this symbol in bash, it's probably
because something is getting expanded. It could be a parameter, or the output of a command, or the result of an arithmetic operation. We'll learn more about the other expansions later on.</p>

<aside class="rule">
<p>We've highlighted this briefly in the previous chapter when we introduced arguments and quoting, but it bears repeating:</p>
<q>Parameter expansions should <strong>always</strong> be double-quoted.</q>
<p>This prevents bash's word-splitting from unexpectedly tearing it to pieces.</p>
<p>You might notice a trend here, but it bears consistent repeating:<br>
<q>Parameter expansions (and all other value expansions) should <strong>always</strong> be double-quoted.</q></p>
</aside>

<p>In addition, parameter expansion allows you to wrap curly braces (<kbd>{</kbd> and <kbd>}</kbd>) around your expansion. These braces are used to tell bash what the beginning and end of your parameter name is. They are usually optional, as bash can often figure the name out by itself. Though sometimes they become a necessity:</p>
Expand Down
8 changes: 6 additions & 2 deletions _sass/_layout.scss
Expand Up @@ -231,12 +231,13 @@ div.status {
}
}
section {
h1, h2, p {
&>h1, &>h2, &>h3, &>p, &>dl>dt, &>aside {
position: relative;
padding: 0.5ex;

.bookmark {
position: absolute;
top: 0.5ex;
margin-left: -2em;
padding-right: 1.5em;
height: 100%;
Expand All @@ -247,9 +248,12 @@ section {
background: rgba(100, 200, 255, 0.2);
}
}
&>aside .bookmark {
padding-top: 1.2em;
}
}
section {
h1, h2, p {
&>h1, &>h2, &>h3, &>p, &>dl>dt, &>aside {
&:hover {
.bookmark {
display: block;
Expand Down
35 changes: 30 additions & 5 deletions js/main.js
Expand Up @@ -66,27 +66,52 @@ $(function(){
});

// Add paragraph and heading links.
var h1 = 0, h2 = 0, p = 0;
$('section h1, section h2, section p').each(function() {
var id = '';
var h1 = 0, h2 = 0, h3 = 0, p = 0, t = 0, a = 0, scope_hint = '';
$('section>h1, section>h2, section>h3, section>p, section>dl>dt, section>aside').each(function() {
var id = '', hint = scope_hint;
if ("h1" == this.tagName.toLowerCase()) {
++h1;
h2 = 0;
h3 = 0;
p = 0;
t = 0;
a = 0;
id = 'h' + h1;
hint = scope_hint = this.innerText.replace(/ /g, '_')
}
else if ("h2" == this.tagName.toLowerCase()) {
++h2;
h3 = 0;
p = 0;
t = 0;
a = 0;
id = 'h' + h1 + '.' + h2;
hint = scope_hint = this.innerText.replace(/ /g, '_')
}
else if ("h3" == this.tagName.toLowerCase()) {
++h3;
p = 0;
t = 0;
a = 0;
id = 'h' + h1 + '.' + h2 + '.' + h3;
hint = scope_hint = this.innerText.replace(/ /g, '_')
}
else if ("p" == this.tagName.toLowerCase()) {
++p;
id = 'p' + h1 + '.' + h2 + '_' + p;
id = 'p' + h1 + '.' + h2 + '.' + h3 + '_' + p;
}
else if ("dt" == this.tagName.toLowerCase()) {
++t;
id = 't' + h1 + '.' + h2 + '.' + h3 + '_' + t;
hint = this.innerText.replace(/ /g, '_')
}
else if ("aside" == this.tagName.toLowerCase()) {
++a;
id = 'a' + h1 + '.' + h2 + '.' + h3 + '_' + a;
}

$(this).attr('id', id);
$('<a>#</a>').prependTo(this).addClass('bookmark').attr('href', '#' + id);
$('<a>#</a>').prependTo(this).addClass('bookmark').attr('href', (hint? '?=' + hint: '') + '#' + id);
});
});

0 comments on commit 0bc2c46

Please sign in to comment.