Skip to content

Commit 29cac54

Browse files
typo correction and changes based on self review
1 parent 8c19624 commit 29cac54

18 files changed

+47
-37
lines changed

calculator/calc_bash_func.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
3939
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
4040
});
41-
</script><div id=content class=content><main><div class=sidetoc><nav class=pagetoc></nav></div><h1 id=bash-shortcuts><a class=header href=#bash-shortcuts>Bash shortcuts</a></h1><p>In this section, you'll see how to execute Python instructions from the command line and use shell shortcuts to create simple CLI applications. This project uses <code>bash</code> as the shell to showcase examples.<h2 id=python-cli-options><a class=header href=#python-cli-options>Python CLI options</a></h2><p>Passing a file to the interpreter from the command line is one of the ways to execute a Python program. You can also use <code>-c</code> option to directly pass instructions to be executed as an argument. This is suitable for small programs, like getting the result of a mathematical expression. Here's an example:<pre><code class=language-bash>$ python3.9 -c 'print(5 ** 2)'
41+
</script><div id=content class=content><main><div class=sidetoc><nav class=pagetoc></nav></div><h1 id=bash-shortcuts><a class=header href=#bash-shortcuts>Bash shortcuts</a></h1><p>In this section, you'll see how to execute Python instructions from the command line and use shell shortcuts to create simple CLI applications. This project uses <code>bash</code> as the shell to showcase examples.<h2 id=python-cli-options><a class=header href=#python-cli-options>Python CLI options</a></h2><p>Passing a file to the interpreter from the command line is one of the ways to execute a Python program. You can also use <code>-c</code> option to directly pass instructions to be executed as an argument. This is suitable for small programs, like getting the result of a mathematical expression. Here's an example:<pre><code class=language-bash># use py instead of python3.9 for Windows
42+
$ python3.9 -c 'print(5 ** 2)'
4243
25
4344
</code></pre><blockquote><p><img src=../images/info.svg alt=info> Use <code>python3.9 -h</code> to see all the available options. See <a href=https://docs.python.org/3/using/cmdline.html>docs.python: Command line and environment</a> for documentation.</blockquote><h2 id=python-repl><a class=header href=#python-repl>Python REPL</a></h2><p>If you call the interpreter without passing instructions to be executed, you'll get an interactive console known as REPL (stands for <strong>R</strong>ead <strong>E</strong>valuate <strong>P</strong>rint <strong>L</strong>oop). This is typically used to execute instructions for learning and debugging purposes. REPL is well suited to act as a calculator too. Since the result of an expression is automatically printed, you don't need to explicitly call <code>print()</code> function. A special variable <code>_</code> holds the result of the last executed expression. Here's some examples:<pre><code class=language-bash>$ python3.9 -q
4445
>>> 2 * 31 - 3
@@ -48,7 +49,7 @@
4849
>>> exit()
4950
</code></pre><p>See also:<ul><li><a href=https://docs.python.org/3/tutorial/interpreter.html>docs.python: Using the Python Interpreter</a><li><a href=https://docs.python.org/3/tutorial/introduction.html#using-python-as-a-calculator>docs.python: Using Python as a Calculator</a><li><a href=https://ipython.readthedocs.io/en/stable/interactive/tutorial.html>IPython</a> — an alternate feature-rich Python REPL</ul><h2 id=bash-function><a class=header href=#bash-function>Bash function</a></h2><p>Calling <code>print()</code> function via <code>-c</code> option from the command line is simple enough. But you could further simplify by creating a CLI application using a <code>bash</code> function as shown below.<pre><code class=language-bash># bash_func.sh
5051
pc() { python3.9 -c 'print('"$1"')' ; }
51-
</code></pre><p>You can type that on your current active terminal or add it your <code>.bashrc</code> file so that the shortcut is always available for use. The function is named <code>pc</code> (short for Python Calculator). The first argument passed to <code>pc</code> in turn is passed along as the argument for Python's <code>print()</code> function. To see how <code>bash</code> processes this user defined function, you can use <code>set -x</code> as shown below. See <a href=https://unix.stackexchange.com/questions/155551/how-to-debug-a-bash-script>unix.stackexchange: How to debug a bash script?</a> for more details.<pre><code class=language-bash>$ set -x
52+
</code></pre><p>You can type that on your current active terminal or add it your <code>.bashrc</code> file so that the shortcut is always available for use (assuming <code>pc</code> isn't an existing command). The function is named <code>pc</code> (short for Python Calculator). The first argument passed to <code>pc</code> in turn is passed along as the argument for Python's <code>print()</code> function. To see how <code>bash</code> processes this user defined function, you can use <code>set -x</code> as shown below. See <a href=https://unix.stackexchange.com/questions/155551/how-to-debug-a-bash-script>unix.stackexchange: How to debug a bash script?</a> for more details.<pre><code class=language-bash>$ set -x
5253
$ pc '40 + 2'
5354
+ pc '40 + 2'
5455
+ python3.9 -c 'print(40 + 2)'
@@ -73,7 +74,7 @@
7374
5.846153846153846
7475
$ pc '76 // 13'
7576
5
76-
</code></pre><blockquote><p><img src=../images/info.svg alt=info> See also <a href=https://unix.stackexchange.com/questions/30925/in-bash-when-to-alias-when-to-script-and-when-to-write-a-function/>unix.stackexchange: when to use alias, functions and scripts</a></blockquote><h2 id=accepting-stdin><a class=header href=#accepting-stdin>Accepting stdin</a></h2><p>Many CLI applications allow you to pass <code>stdin</code> data as input. To add that functionality, you can use <code>if</code> statement to read a line from standard input if the number of arguments is zero or if the argument passed is <code>-</code> character. The modified <code>pc</code> function is shown below:<pre><code class=language-bash># bash_func_stdin.sh
77+
</code></pre><blockquote><p><img src=../images/info.svg alt=info> See also <a href=https://unix.stackexchange.com/questions/30925/in-bash-when-to-alias-when-to-script-and-when-to-write-a-function/>unix.stackexchange: when to use alias, functions and scripts</a></blockquote><h2 id=accepting-stdin><a class=header href=#accepting-stdin>Accepting stdin</a></h2><p>Many CLI applications allow you to pass <code>stdin</code> data as input. To add that functionality, you can use <code>if</code> statement to read a line from standard input if the number of arguments is zero or <code>-</code> character is passed as the argument. The modified <code>pc</code> function is shown below:<pre><code class=language-bash># bash_func_stdin.sh
7778
pc()
7879
{
7980
ip_expr="$1"

calculator/calc_py_cli.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
3939
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
4040
});
41-
</script><div id=content class=content><main><div class=sidetoc><nav class=pagetoc></nav></div><h1 id=python-cli-application><a class=header href=#python-cli-application>Python CLI application</a></h1><p>In this section, you'll see how to implement a CLI application using Python features, instead of relying on shell features. First, you'll learn how to work with command line arguments using the <code>sys</code> module. Followed by <code>argparse</code> module, which is specifically designed for creating CLI applications.<h2 id=sysargv><a class=header href=#sysargv>sys.argv</a></h2><p>Command line arguments passed when executing a Python program can be accessed using the <code>sys.argv</code> list. The first element (index <code>0</code>) contains the name of the Python script or <code>-c</code> or empty string, depending on how the interpreter was called. See <a href=https://docs.python.org/3/library/sys.html#sys.argv>docs.python: sys.argv</a> for details.<p>Rest of the elements will have the command line arguments, if any were passed along the script to be executed. The data type of <code>sys.argv</code> elements is <code>str</code> class. The <code>eval()</code> function allows to execute a string as a Python instruction. Here's an example:<pre><code class=language-bash>$ python3.9 -c 'import sys; print(eval(sys.argv[1]))' '23 ** 2'
41+
</script><div id=content class=content><main><div class=sidetoc><nav class=pagetoc></nav></div><h1 id=python-cli-application><a class=header href=#python-cli-application>Python CLI application</a></h1><p>In this section, you'll see how to implement a CLI application using Python features, instead of relying on shell features. First, you'll learn how to work with command line arguments using the <code>sys</code> module. Followed by <code>argparse</code> module, which is specifically designed for creating CLI applications.<h2 id=sysargv><a class=header href=#sysargv>sys.argv</a></h2><p>Command line arguments passed when executing a Python program can be accessed using the <code>sys.argv</code> list. The first element (index <code>0</code>) contains the name of the Python script or <code>-c</code> or empty string, depending on how the interpreter was called. See <a href=https://docs.python.org/3/library/sys.html#sys.argv>docs.python: sys.argv</a> for details.<p>Rest of the elements will have the command line arguments, if any were passed along the script to be executed. The data type of <code>sys.argv</code> elements is <code>str</code> class. The <code>eval()</code> function allows you to execute a string as a Python instruction. Here's an example:<pre><code class=language-bash>$ python3.9 -c 'import sys; print(eval(sys.argv[1]))' '23 ** 2'
4242
529
4343

4444
# bash shortcut
@@ -47,7 +47,7 @@
4747
529
4848
$ pc '0x2F'
4949
47
50-
</code></pre><blockquote><p><img src=../images/warning.svg alt=warning> <img src=../images/warning.svg alt=warning> Using <code>eval()</code> function isn't recommended if the input passed to it isn't under your control, for example an input typed by a user from a website application. The arbitrary code execution issue would apply to the <code>bash</code> shortcuts seen in previous section as well, because the input argument is interpreted without any sanity check. However, for the purpose of this calculator project, it is assumed that you are the sole user of the application. See <a href=https://stackoverflow.com/questions/2371436/evaluating-a-mathematical-expression-in-a-string>stackoverflow: evaluating a mathematical expression</a> for more details about the dangers of using <code>eval()</code> function and alternate ways to evaluate a string as mathematical expression.</blockquote><h2 id=argparse><a class=header href=#argparse>argparse</a></h2><p>Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>argparse</code> module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and <code>argparse</code> will figure out how to parse those out of <code>sys.argv</code>. The <code>argparse</code> module also automatically generates help and usage messages and issues errors when users give the program invalid arguments.</blockquote><h2 id=argparse-initialization><a class=header href=#argparse-initialization>argparse initialization</a></h2><p>If this is your first time using the <code>argparse</code> module, it is recommended to understand the initialization instructions and see the effect they provide by default. Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>ArgumentParser</code> object will hold all the information necessary to parse the command line into Python data types.</blockquote><blockquote><p><code>ArgumentParser</code> parses arguments through the <code>parse_args()</code> method. This will inspect the command line, convert each argument to the appropriate type and then invoke the appropriate action.</blockquote><pre><code class=language-python># arg_help.py
50+
</code></pre><blockquote><p><img src=../images/warning.svg alt=warning> <img src=../images/warning.svg alt=warning> Using <code>eval()</code> function isn't recommended if the input passed to it isn't under your control, for example an input typed by a user from a website application. The arbitrary code execution issue would apply to the <code>bash</code> shortcuts seen in previous section as well, because the input argument is interpreted without any sanity check.<p>However, for the purpose of this calculator project, it is assumed that you are the sole user of the application. See <a href=https://stackoverflow.com/q/2371436/4082052>stackoverflow: evaluating a mathematical expression</a> for more details about the dangers of using <code>eval()</code> function and alternate ways to evaluate a string as mathematical expression.</blockquote><h2 id=argparse><a class=header href=#argparse>argparse</a></h2><p>Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>argparse</code> module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and <code>argparse</code> will figure out how to parse those out of <code>sys.argv</code>. The <code>argparse</code> module also automatically generates help and usage messages and issues errors when users give the program invalid arguments.</blockquote><h2 id=argparse-initialization><a class=header href=#argparse-initialization>argparse initialization</a></h2><p>If this is your first time using the <code>argparse</code> module, it is recommended to understand the initialization instructions and see the effect they provide by default. Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>ArgumentParser</code> object will hold all the information necessary to parse the command line into Python data types.<p><code>ArgumentParser</code> parses arguments through the <code>parse_args()</code> method. This will inspect the command line, convert each argument to the appropriate type and then invoke the appropriate action.</blockquote><pre><code class=language-python># arg_help.py
5151
import argparse
5252

5353
parser = argparse.ArgumentParser()
@@ -141,7 +141,7 @@
141141
print(result)
142142
except (NameError, SyntaxError):
143143
sys.exit("Error: Not a valid input expression")
144-
</code></pre><p>The <code>type</code> parameter for <code>add_argument()</code> method allows you to specify what data type should be applied for that option. The <code>-f</code> option is used here to set the precision for floating-point output. The code doesn't actually check if the output is floating-point type, that is left as an exercise for you.<p>The <code>-b</code>, <code>-o</code>, <code>-x</code> and <code>-v</code> options are intended as boolean data type. Using <code>action="store_true"</code> indicates that the associated attribute should be set to <code>False</code> as their default value. When the option is used from the command line, their value will be set to <code>True</code>. The <code>-b</code>, <code>-o</code> and <code>-x</code> options are used here to get the output in binary, octal and hexadecimal formats respectively. The <code>-v</code> option will print both the input expression and the evaluated result.<p>The help documentation for this script is shown below. By default, uppercase of the option name will be used to describe the value expected for that option. Which is why you see <code>-f F</code> here. You can use <code>metavar='precision'</code> to change it to <code>-f precision</code> instead.<pre><code class=language-bash>$ python3.9 options.py -h
144+
</code></pre><p>The <code>type</code> parameter for <code>add_argument()</code> method allows you to specify what data type should be applied for that option. The <code>-f</code> option is used here to set the precision for floating-point output. The code doesn't actually check if the output is floating-point type, that is left as an exercise for you.<p>The <code>-b</code>, <code>-o</code>, <code>-x</code> and <code>-v</code> options are intended as boolean data types. Using <code>action="store_true"</code> indicates that the associated attribute should be set to <code>False</code> as their default value. When the option is used from the command line, their value will be set to <code>True</code>. The <code>-b</code>, <code>-o</code> and <code>-x</code> options are used here to get the output in binary, octal and hexadecimal formats respectively. The <code>-v</code> option will print both the input expression and the evaluated result.<p>The help documentation for this script is shown below. By default, uppercase of the option name will be used to describe the value expected for that option. Which is why you see <code>-f F</code> here. You can use <code>metavar='precision'</code> to change it to <code>-f precision</code> instead.<pre><code class=language-bash>$ python3.9 options.py -h
145145
usage: options.py [-h] [-f F] [-b] [-o] [-x] [-v] ip_expr
146146

147147
positional arguments:
@@ -223,7 +223,7 @@
223223
print(result)
224224
except (NameError, SyntaxError):
225225
sys.exit("Error: Not a valid input expression")
226-
</code></pre><p>The <code>nargs</code> parameter allows to specify how many arguments can be accepted with a single action. You can use an integer value to get that many arguments as a list or use specific regular expression like metacharacter to indicate varying number of arguments. The <code>ip_expr</code> argument is made optional here by setting <code>nargs</code> to <code>?</code>.<p>If <code>ip_expr</code> isn't passed as an argument by the user, the attribute will get <code>None</code> as the value. The <code>-</code> character is often used to indicate <code>stdin</code> as the input data. So, if <code>ip_expr</code> is <code>None</code> or <code>-</code>, the code will try to read a line from <code>stdin</code> as the input expression. The <code>strip()</code> string method is applied to the <code>stdin</code> data mainly to prevent newline from messing up the output for <code>-v</code> option. Rest of the code is the same as seen before.<p>The help documentation for this script is shown below. The only difference is that the input expression is now optional as indicated by <code>[ip_expr]</code>.<pre><code class=language-bash>$ python3.9 py_calc.py -h
226+
</code></pre><p>The <code>nargs</code> parameter allows to specify how many arguments can be accepted with a single action. You can use an integer value to get that many arguments as a list or use specific regular expression like metacharacters to indicate varying number of arguments. The <code>ip_expr</code> argument is made optional here by setting <code>nargs</code> to <code>?</code>.<p>If <code>ip_expr</code> isn't passed as an argument by the user, the attribute will get <code>None</code> as the value. The <code>-</code> character is often used to indicate <code>stdin</code> as the input data. So, if <code>ip_expr</code> is <code>None</code> or <code>-</code>, the code will try to read a line from <code>stdin</code> as the input expression. The <code>strip()</code> string method is applied to the <code>stdin</code> data mainly to prevent newline from messing up the output for <code>-v</code> option. Rest of the code is the same as seen before.<p>The help documentation for this script is shown below. The only difference is that the input expression is now optional as indicated by <code>[ip_expr]</code>.<pre><code class=language-bash>$ python3.9 py_calc.py -h
227227
usage: py_calc.py [-h] [-f F] [-b] [-o] [-x] [-v] [ip_expr]
228228

229229
positional arguments:

0 commit comments

Comments
 (0)