├── .editorconfig ├── .eslintrc.json ├── .github └── workflows │ └── gatsby.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── csv.js ├── gatsby-config.js ├── gatsby-node.js ├── lessons ├── anatomoy-of-a-cli-command.md ├── apt.md ├── conclusion.md ├── conditionals.md ├── cron.md ├── curl.md ├── customize-your-shell.md ├── environments.md ├── errata.md ├── images │ ├── FrontendMastersLogo.png │ ├── brian.jpg │ ├── curl.png │ ├── incident.png │ ├── linux_kernel_map.png │ ├── linux_timeline.png │ ├── logo.svg │ ├── lolcat.png │ ├── multipass.png │ ├── nano.png │ ├── penguin.png │ ├── real_programmers.png │ ├── sandwich.png │ ├── sudo.jpg │ ├── up-and-running.png │ └── vim.png ├── interacting-with-files.md ├── intro.md ├── lets-run-linux.md ├── loops.md ├── nano.md ├── process-operators.md ├── processes.md ├── sftp.md ├── signals-and-the-power-of-ctrl.md ├── snaps.md ├── ssh.md ├── streams-and-pipes.md ├── tips-and-tricks.md ├── users-groups-and-permissions.md ├── variables.md ├── vim.md ├── wget.md ├── what-is-linux.md ├── what-is-package-management.md ├── what-you-will-learn.md ├── wildcards-and-replacements.md └── writing-your-own-scripts.md ├── package-lock.json ├── package.json ├── src ├── components │ ├── TOCCard.css │ └── TOCCard.js ├── layouts │ ├── index.css │ └── index.js ├── pages │ ├── 404.js │ ├── index.css │ └── index.js ├── templates │ └── lessonTemplate.js └── util │ └── helpers.js └── static ├── HEADER.png ├── TOC.png ├── WALLPAPER.jpg ├── WORDMARK-Small.png └── posterframe.jpg /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:import/errors", 5 | "plugin:react/recommended", 6 | "plugin:jsx-a11y/recommended", 7 | "prettier", 8 | "prettier/react" 9 | ], 10 | "rules": { 11 | "react/prop-types": 0, 12 | "jsx-a11y/label-has-for": 0, 13 | "no-console": 1 14 | }, 15 | "plugins": ["react", "import", "jsx-a11y"], 16 | "parser": "babel-eslint", 17 | "parserOptions": { 18 | "ecmaVersion": 2018, 19 | "sourceType": "module", 20 | "ecmaFeatures": { 21 | "jsx": true 22 | } 23 | }, 24 | "env": { 25 | "es6": true, 26 | "browser": true, 27 | "node": true 28 | }, 29 | "settings": { 30 | "react": { 31 | "version": "16.5.2" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/gatsby.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Gatsby Site to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | - name: npm install, build, and csv 14 | run: | 15 | npm install 16 | npm run build 17 | npm run csv 18 | - name: Deploy 🚀 19 | uses: JamesIves/github-pages-deploy-action@4.1.5 20 | with: 21 | branch: gh-pages 22 | folder: public 23 | token: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project dependencies 2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 3 | node_modules 4 | .cache/ 5 | # Build directory 6 | public/ 7 | .DS_Store 8 | yarn-error.log 9 | Thumbs.db 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ## creative commons 2 | 3 | # Attribution-NonCommercial 4.0 International 4 | 5 | Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. 6 | 7 | ### Using Creative Commons Public Licenses 8 | 9 | Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. 10 | 11 | * __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). 12 | 13 | * __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). 14 | 15 | ## Creative Commons Attribution-NonCommercial 4.0 International Public License 16 | 17 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 18 | 19 | ### Section 1 – Definitions. 20 | 21 | a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 22 | 23 | b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 24 | 25 | c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 26 | 27 | d. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 28 | 29 | e. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 30 | 31 | f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 32 | 33 | g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 34 | 35 | h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. 36 | 37 | i. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. 38 | 39 | j. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 40 | 41 | k. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 42 | 43 | l. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 44 | 45 | ### Section 2 – Scope. 46 | 47 | a. ___License grant.___ 48 | 49 | 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: 50 | 51 | A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and 52 | 53 | B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. 54 | 55 | 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 56 | 57 | 3. __Term.__ The term of this Public License is specified in Section 6(a). 58 | 59 | 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 60 | 61 | 5. __Downstream recipients.__ 62 | 63 | A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. 64 | 65 | B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 66 | 67 | 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 68 | 69 | b. ___Other rights.___ 70 | 71 | 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 72 | 73 | 2. Patent and trademark rights are not licensed under this Public License. 74 | 75 | 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. 76 | 77 | ### Section 3 – License Conditions. 78 | 79 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 80 | 81 | a. ___Attribution.___ 82 | 83 | 1. If You Share the Licensed Material (including in modified form), You must: 84 | 85 | A. retain the following if it is supplied by the Licensor with the Licensed Material: 86 | 87 | i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); 88 | 89 | ii. a copyright notice; 90 | 91 | iii. a notice that refers to this Public License; 92 | 93 | iv. a notice that refers to the disclaimer of warranties; 94 | 95 | v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 96 | 97 | B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and 98 | 99 | C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 100 | 101 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 102 | 103 | 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 104 | 105 | 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. 106 | 107 | ### Section 4 – Sui Generis Database Rights. 108 | 109 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 110 | 111 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; 112 | 113 | b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and 114 | 115 | c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 116 | 117 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 118 | 119 | ### Section 5 – Disclaimer of Warranties and Limitation of Liability. 120 | 121 | a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ 122 | 123 | b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ 124 | 125 | c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 126 | 127 | ### Section 6 – Term and Termination. 128 | 129 | a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 130 | 131 | b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 132 | 133 | 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 134 | 135 | 2. upon express reinstatement by the Licensor. 136 | 137 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 138 | 139 | c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 140 | 141 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 142 | 143 | ### Section 7 – Other Terms and Conditions. 144 | 145 | a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 146 | 147 | b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. 148 | 149 | ### Section 8 – Interpretation. 150 | 151 | a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 152 | 153 | b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 154 | 155 | c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 156 | 157 | d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 158 | 159 | > Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. 160 | > 161 | > Creative Commons may be contacted at creativecommons.org -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Complete Intro to Linux and the CLI](/static/WORDMARK-Small.png)][course] 2 | 3 | [![Frontend Masters](/lessons/images/FrontendMastersLogo.png)][fem] 4 | 5 | - [Please click here][website] to head to the course website. 6 | - See the [course on Frontend Masters][course] 7 | 8 | # Issues and Pull Requests 9 | 10 | Please file issues and open pull requests here! Thank you! 11 | 12 | # License 13 | 14 | The content of this workshop is licensed under CC-BY-NC-4.0. Feel free to share freely but do not resell my content. 15 | 16 | The code, including the code of the site itself and the code in the exercises, are licensed under Apache 2.0. 17 | 18 | [website]: https://bit.ly/linux-cli 19 | [fem]: https://www.frontendmasters.com 20 | [course]: https://frontendmasters.com/courses/linux-command-line/ 21 | -------------------------------------------------------------------------------- /csv.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs").promises; 2 | const path = require("path"); 3 | const fm = require("front-matter"); 4 | const isUrl = require("is-url-superb"); 5 | const parseLinks = require("parse-markdown-links"); 6 | const { sorter } = require("./src/util/helpers"); 7 | const mdDir = process.env.MARKDOWN_DIR || path.join(__dirname, "lessons/"); 8 | const outputPath = 9 | process.env.OUTPUT_CSV_PATH || path.join(__dirname, "public/lessons.csv"); 10 | const linksOutputPath = 11 | process.env.LINKS_CSV_PATH || path.join(__dirname, "public/links.csv"); 12 | 13 | async function createCsv() { 14 | console.log(`making the markdown files into a CSV from ${mdDir}`); 15 | 16 | // get paths 17 | const allFiles = await fs.readdir(mdDir); 18 | const files = allFiles.filter(filePath => filePath.endsWith(".md")); 19 | 20 | // read paths, get buffers 21 | const buffers = await Promise.all( 22 | files.map(filePath => fs.readFile(path.join(mdDir, filePath))) 23 | ); 24 | 25 | // make buffers strings 26 | const contents = buffers.map(content => content.toString()); 27 | 28 | // make strings objects 29 | let frontmatters = contents.map(fm); 30 | 31 | // find all attribute keys 32 | const seenAttributes = new Set(); 33 | frontmatters.forEach(item => { 34 | Object.keys(item.attributes).forEach(attr => seenAttributes.add(attr)); 35 | }); 36 | const attributes = Array.from(seenAttributes.values()); 37 | 38 | if (attributes.includes("order")) { 39 | frontmatters = frontmatters.sort(sorter); 40 | } 41 | 42 | // get all data into an array 43 | let rows = frontmatters.map(item => { 44 | const row = attributes.map(attr => 45 | item.attributes[attr] ? JSON.stringify(item.attributes[attr]) : "" 46 | ); 47 | return row; 48 | }); 49 | 50 | // header row must be first row 51 | rows.unshift(attributes); 52 | 53 | // join into CSV string 54 | const csv = rows.map(row => row.join(",")).join("\n"); 55 | 56 | // write file out 57 | await fs.writeFile(outputPath, csv); 58 | 59 | console.log(`Wrote ${rows.length} rows to ${outputPath}`); 60 | 61 | // make links csv 62 | let longestLength = 0; 63 | let linksArray = frontmatters.map(row => { 64 | const links = parseLinks(row.body).filter(isUrl); 65 | longestLength = longestLength > links.length ? longestLength : links.length; 66 | const newRow = [row.attributes.order, row.attributes.title, ...links]; 67 | return newRow; 68 | }); 69 | 70 | if (longestLength) { 71 | // add title row 72 | linksArray = linksArray.map(array => { 73 | const lengthToFill = longestLength + 2 - array.length; 74 | return array.concat(Array.from({ length: lengthToFill }).fill("")); 75 | }); 76 | 77 | linksArray.unshift( 78 | ["order", "title"].concat( 79 | Array.from({ length: longestLength }).map((_, index) => `link${index}`) 80 | ) 81 | ); 82 | 83 | // join into CSV string 84 | const linksCsv = linksArray.map(row => row.join(",")).join("\n"); 85 | 86 | // write file out 87 | await fs.writeFile(linksOutputPath, linksCsv); 88 | 89 | console.log(`Wrote ${linksArray.length} rows to ${linksOutputPath}`); 90 | } 91 | } 92 | 93 | createCsv(); 94 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: "Complete Intro to Linux and the CLI", 4 | subtitle: "Learn how to use the command", 5 | description: 6 | "The complete intro to using Linux and the command line as taught by Brian Holt", 7 | keywords: [ 8 | "linux", 9 | "ubuntu", 10 | "command line", 11 | "cli", 12 | "javascript", 13 | "bash", 14 | "zsh", 15 | "js" 16 | ] 17 | }, 18 | pathPrefix: "/complete-intro-to-linux-and-the-cli", 19 | plugins: [ 20 | `gatsby-plugin-sharp`, 21 | `gatsby-plugin-layout`, 22 | { 23 | resolve: `gatsby-source-filesystem`, 24 | options: { 25 | path: `${__dirname}/lessons`, 26 | name: "markdown-pages" 27 | } 28 | }, 29 | `gatsby-plugin-react-helmet`, 30 | { 31 | resolve: `gatsby-transformer-remark`, 32 | options: { 33 | plugins: [ 34 | `gatsby-remark-autolink-headers`, 35 | `gatsby-remark-copy-linked-files`, 36 | `gatsby-remark-prismjs`, 37 | { 38 | resolve: `gatsby-remark-images`, 39 | options: { 40 | maxWidth: 800, 41 | linkImagesToOriginal: true, 42 | sizeByPixelDensity: false 43 | } 44 | } 45 | ] 46 | } 47 | } 48 | ] 49 | }; 50 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | exports.createPages = ({ actions, graphql }) => { 4 | const { createPage } = actions; 5 | 6 | const lessonTemplate = path.resolve(`src/templates/lessonTemplate.js`); 7 | 8 | return graphql(` 9 | { 10 | allMarkdownRemark( 11 | sort: { order: DESC, fields: [frontmatter___order] } 12 | limit: 1000 13 | ) { 14 | edges { 15 | node { 16 | excerpt(pruneLength: 250) 17 | html 18 | id 19 | frontmatter { 20 | order 21 | path 22 | title 23 | } 24 | } 25 | } 26 | } 27 | } 28 | `).then(result => { 29 | if (result.errors) { 30 | return Promise.reject(result.errors); 31 | } 32 | 33 | result.data.allMarkdownRemark.edges.forEach(({ node }) => { 34 | createPage({ 35 | path: node.frontmatter.path, 36 | component: lessonTemplate 37 | }); 38 | }); 39 | }); 40 | }; 41 | -------------------------------------------------------------------------------- /lessons/anatomoy-of-a-cli-command.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/anatomy-of-a-cli-command" 3 | title: "Anatomy of a CLI Command" 4 | order: "3A" 5 | section: "The CLI" 6 | description: "Brian talk about what the command line is, why you'd want to use it, and how to get started with it" 7 | --- 8 | 9 | So now you should have a Linux command line open and ready to go. If this is your first experience with a command line prompt, don't worry! This course was made for you! We'll go through together what this strange beast is. 10 | 11 | What you're looking at is often called a REPL, a **R**ead **E**valuate **P**rint **L**oop. It's basically an interactive way of programming where you're writing one line of code at a time, feeding data in and out of little programs. Using commands here, you can navigate around you computer, read and write data, make network calls, and all sorts of other stuff. Basically most anything you can do with a desktop you can do with a command line, it's just a little less obvious how to do it. 12 | 13 | The way a REPL works is that you send one command at a time and the shell runs the command and returns to you a result. During the course of running that one command, it may print some things out. And you can, using some rudimentary programming syntax, write a line that runs multiple times (or, another way of saying "runs multiple times" is looping.) That's it! That's whole concept of what we're going to learning today. 14 | 15 | # Shells and Emulators 16 | 17 | The first thing we should do is get some terminology out of the way. You are using a **shell** right now, and that shell is almost certainly called [bash][bash] (it definitely is unless you changed something), the **B**ourne **A**gain **Sh**ell (which is making fun of the Bourne shell which bash replaced.) It's by far the most common shell and is over 30 years old. 18 | 19 | There are other shells and we'll talk more about them later, the most common of which are zsh, ash, PowerShell, and cmd.exe. We'll chat about those later. 20 | 21 | Your shell is running inside some sort of emulator. That emulator could be Terminal.app or iTerm2 if you're on macOS, or it could be the Windows Terminal if you're on Windows 10. This the window that's containing the shell, and you can use that emulator to switch out what shell is running inside of it. For now we want to be on bash (or zsh is basically the same too.) 22 | 23 | # File System 24 | 25 | The way bash works is that you are always in a folder somewhere on your computer. Think of it like your computer's File Explorer or Finder: you can navigate into and out of folders while you look for files. 26 | 27 | Our first command we're going to run in your computer is `pwd`. So type `pwd` and hit enter. This will send the command `pwd` to the shell which will evaluate that and print out the answer. 28 | 29 | `pwd` is a little program that tells you the current **path** of where you are in the file system. `pwd` stands for present working directory. It's basically like asking the computer "where am I right now?" Mine says `/home/ubuntu`. I am inside of the `ubuntu` folder which itself is inside of the `home` directory. The terms **folder** and **directory** are interchangeable and I say both all the time. 30 | 31 | This is what paths look like, `///`. The `/` represents a level of nesting inside of another folder. The **root** directory is at `/`. 32 | 33 | So by typing pwd, we've successfully run our first program! Congrats! 34 | 35 | # Help 36 | 37 | I forget all the time how to use various different programs. `pwd` is very simple but others are way more complex. For _most_ programs, you can add `--help` at the end and it'll usually spit out some brief instructions of how to use the program. This one isn't super necessary right now but go ahead and type `pwd --help` to see its help text. `--help` is called a **flag**. We'll talk more about those later. 38 | 39 | # Navigating Around 40 | 41 | So right now we're in the home directory of the `ubuntu` user if you've been following along with me. Every user gets their own folder in the `/home` folder. Since our user is named ubuntu, they have their own folder called ubuntu. Let's first see if we have any files inside of our home directory. Type `ls` and hit enter. `ls` stands for list, and it means show me everything inside of the folder where I am. 42 | 43 | I see two things, `Home` and `snap`. I don't know what those are or why they're there but I assume it's something that Ubuntu creates for you. Let's navigate outside of our home directory and into the `/home` directory. We'll use a different program called `cd` to do that. `cd` stands for change directory. Type `cd ..` and hit enter. 44 | 45 | `..` is shorthand that means "up one directory." Because I wanted to go from `/home/ubuntu` to `/home`, I sent the command `cd ..` and that `..` means up one directory. There's also `.` which means "this directory". So you if you say `cd .` you won't go anywhere! It means change directory to this directory that we're already in, which doesn't do anything. 46 | 47 | Type `ls` again. I only see one thing in there, `ubuntu`. If we type `cd ubuntu` we'll navigate back into the ubuntu directory. Between `ls`, `cd`, and `pwd`, you can navigate basically anywhere on your computer. 48 | 49 | `..` and `.` are called relative paths. They're paths which are relative to where you are. You can also give `cd` an absolute path as well. If we say `cd /home/ubuntu`, it'll navigate directly to that folder from anywhere. It's like the difference between saying "I live at 123 Main St in Seattle" (an absolute path) and "I left three houses down from here" (a relative path.) The first refers to the same house no matter where you are in the world whereas the second only makes sense based on where you are. 50 | 51 | ## Arguments / Parameters 52 | 53 | In the case of cd, we're passing data into cd to tell it how to run. If we run `cd ..`, the `..` is an argument or parameter (basically the same thing, for this purpose the two terms can be used interchangeably.) This is just how you pass information into the program so it can do what you want it to do. Not all programs need parameters or sometimes they're optional. Let's look at `pwd`: it never needs any arguments. Or `ls` which has optional arguments. If you say `ls`, it's the same as saying `ls .`. The `.` in this case means "this directory". So if I say `ls ..` it'll give me what's the content of the directory one up from where I am. Or if I say `ls /home` it'll give me the contents of the `home` directory. In these examples, I've given you arguments that happen to be paths but that isn't always true. Arguments are just bits of information you give to a program, frequently they're paths to files or folders but they can often be other things. 54 | 55 | Let's try one that isn't a path, `echo`. Try typing `echo hi`. It should echo back to you "hi". This is useful when you're writing your own scripts to print out things to the user. In this case, "hi" is the parameter. 56 | 57 | Or let's try `which`. `which` will tell you the path to where the program you're running is. If I say `which ls` it'll tell me where `ls` is stored (in my case, `/bin/ls`.) `ls` would be the parameter. 58 | 59 | ## Flags 60 | 61 | We already talked about `--help` which is a flag but this commands can take all sorts of flags to customize how they'll act. Like parameters, they're bits of information that change how the command works. `ls` has lots of flags so let's try that. 62 | 63 | Try `ls` first. Now try `ls -l`. You'll see it's relatively the same content just presented differently. Now it not only shows us what is in the directory, it shows us the permissions of the files (we'll talk about those later), the user who made it, the group that user belongs to, the size of the file in bytes, when it was last modified, and the name of the folder. The `-l` causes ls to use this long format instead of its normal, terse way of listing stuff out. 64 | 65 | Let's try using two flags. Try `ls -l -a`. The `-a` means show hidden files too. Anything that begins with a `.` in Linux is considered a hidden file. These are usually configuration files that don't need to be shown all the time. By passing the `-a` we can tell `ls` to show us all the hidden files too. 66 | 67 | Many programs allow you to be lazy and combine flags together. In this case, we can say `ls -la` and that's the same as `ls -a -l` (order doesn't matter either.) This is usually true but it depends on the individual command you're running. 68 | 69 | I've shown the shorthand way of doing flags, `-a` with one dash and one letter. There's often a long form way of doing it as well. For example, `ls -a` is the same as doing `ls --all`. When you have two dashes, you're doing the long-form way of doing it. That's important because `ls -all` would be passing the flags `-a`, `-l`, and `-l` again (which it would ignore) so it's important to use two dashes to let the program know you mean one flag. You can mix and match too. 70 | 71 | You can pass parameters to flag too. Let's say in our home directory we wanted to not show the `snap` directory in our output. We can use flags to do that. If we type `ls --ignore snap` it will not output snap. This can also be written as `ls --ignore=snap` to make it clearer what that ignore is referring to. We can also say `ls -I snap` for the shorthand. We can't use the equal here. Lastly if we wanted to do an `ls` on the `/home` directory and not show the `ubuntu` folder, we could type `ls --ignore ubuntu /home`. In this particular case, the order is important. Immediately after ignore, the part you're trying to ignore is passed, then the last parameters to `ls` as a whole is passed. This is why some people like that equals. `ls --ignore=ubuntu /home` is very clear. Up to you. 72 | 73 | [bash]: https://en.wikipedia.org/wiki/Bash_(Unix_shell) 74 | -------------------------------------------------------------------------------- /lessons/apt.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/apt" 3 | title: "APT" 4 | order: "8B" 5 | section: "Package Management" 6 | description: "The first tool a developer needs to use for getting packages on Linux is APT. Brian digs into how to get packages and how to find them." 7 | --- 8 | 9 | The first tool of interest is APT, advanced packaging tool. This tool has been around for a while and uses dpkg under the hood. There have been several iterations of it so let's make sure you get what APT is going to do for you and how to use it. 10 | 11 | ## apt-get 12 | 13 | A very confusing thing to me when I first using Linux is sometimes I see commands that use apt-get and other times I'd see just apt. What's the difference? Which one should I use? They both hit the same registry and download the same files. 14 | 15 | apt-get is older than apt. apt-get is a swiss army knife of apt and has a lot of flexibility and power to do different things. It also pairs wth apt-cache to get accomplish some tasks as well. Since some folks got frustrated that apt-get was a bit difficult how to use and where all the correct commands were, they built a layer on top of it to be more user friendly, apt. Therefore I'd recommend you generally ignore apt-get. There's no problem with the tool and it's not going away, it's just apt is easier to use and remember how to use. 16 | 17 | ## apt 18 | 19 | Okay, so let's chat about apt now. apt is a tool that allows you to download new packages via `apt install`. Let's just nab one now for fun. Run `sudo apt install lolcat`. This will go out and fetch the package lolcat from the apt registry and install. After a second it should download and be immediately be available for use. Now try this: `ls -lsah | lolcat`. 20 | 21 | You do need to install packages as root. 22 | 23 | ![lolcat making ls output colorful](./images/lolcat.png) 24 | 25 | Credit to [Sarah Drasner][sarah] for introducing me to this idea. 26 | 27 | This is a fun example of using the extended Debian / Ubuntu ecosystem but there are literally thousands of packages available for you to use through apt. Let's try another one. 28 | 29 | ```bash 30 | node -e "console.log('hi')" # this will fail, Node.js is not installed 31 | apt search nodejs 32 | apt show nodejs 33 | sudo apt install nodejs 34 | node -e "console.log('hi')" 35 | ``` 36 | 37 | Here's a few more commands for you to know 38 | 39 | ```bash 40 | sudo apt autoremove # will remove unused dependencies 41 | sudo apt update # updates the list of available packages apt uses 42 | apt list # everything installed 43 | apt list --upgradable # everything with an update available 44 | sudo apt upgrade # updates all your packages to their latest available versions 45 | sudo apt full-upgrade # basically autoremove and upgrade together 46 | ``` 47 | 48 | That's pretty much it! While there's no official web browser experience for apt, [check out this open source once][apt]. 49 | 50 | [sarah]: https://twitter.com/sarah_edo/status/1249702231407857666 51 | [apt]: https://www.apt-browse.org/ 52 | -------------------------------------------------------------------------------- /lessons/conclusion.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/conclusion" 3 | title: "Conclusion" 4 | order: "10C" 5 | section: "Last Thoughts" 6 | description: "Brian leaves with you some parting knowledge and gives some suggestions on where to go from here." 7 | --- 8 | 9 | You made it! Congratulations. If you followed everything in this course I would definitely put you in the top 50% of developers who use the shell. Many developers never bother to get this level of depth so for that I want to pat you on the back for taking the time to invest into your tools. 10 | 11 | And guess what? Most of what you learned applies outside of just bash and Ubuntu. Nearly everything I taught you will work literally the same in other shells like zsh (the now-default shell for macOS.) I'd say more than half works as-is for Microsoft PowerShell (installed on Windows by default and works on Linux and macOS too.) 12 | 13 | ## Where to go from here 14 | 15 | This course is a cursory looking into the bash but there are many directions to go from here. For specifically command line related things, I recommend you take these courses as good follow ups: 16 | 17 | - [The Complete Intro to Containers][containers] by me! 18 | - [Git In-Depth][git] by the illustrious Nina Zakharenko 19 | - [Full Stack for Frontend Engineers][fullstack] by the phenomenal Jem Young 20 | - [Introduction to Node.js][node] by the fantastic Scott Moss 21 | 22 | [containers]: https://frontendmasters.com/courses/complete-intro-containers/ 23 | [git]: https://frontendmasters.com/courses/git-in-depth/ 24 | [fullstack]: https://frontendmasters.com/courses/fullstack-v2/ 25 | [node]: https://frontendmasters.com/courses/node-js/ 26 | 27 | ## Thanks 28 | 29 | Thanks again <3. Your support makes it possible for me to make these courses. Go out and make the world a better place with your new found skills! 30 | -------------------------------------------------------------------------------- /lessons/conditionals.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/conditionals" 3 | title: "Conditionals" 4 | order: "9C" 5 | section: "Shell Scripts" 6 | description: "In order to write useful bash scripts a developer needs if statements. Brian goes over how to make more complicated scripts using these control structures" 7 | --- 8 | 9 | In order to write useful bash scripts you need if statements. Let's go over how to make more complicated scripts using these control structures. 10 | 11 | ## Conditionals 12 | 13 | A conditional is a statement that only runs if a condition is true. Let's say we want to use the path `~/temp` if the user don't provide an argument. 14 | 15 | ```bash 16 | #! /bin/bash 17 | 18 | DESTINATION=$1 19 | read -p "enter a file prefix: " FILE_PREFIX 20 | 21 | if [ -z $DESTINATION ]; then 22 | echo "no path provided, defaulting to ~/temp" 23 | DESTINATION=~/temp 24 | fi 25 | 26 | mkdir -p $DESTINATION 27 | cd $DESTINATION 28 | touch ${FILE_PREFIX}{1..10}.txt 29 | echo done 30 | ``` 31 | 32 | The `[]` are a special notation which actually translate to `test` commands. So our condition actually evaluates to `test -z $DESTINATION`. This is useful to know because if you forget how to do conditional checks you can always run `man test` and it's a pretty understandable list of the various things you can do. In this case, `-z $DESTINATION` is checking to see if DESTINATION is a zero length string which would mean the user didn't provide anything. Go ahead and try 33 | 34 | ```bash 35 | test -z "" 36 | echo $? # 0, this is true 37 | test -z "lol" 38 | echo $? # 1, this is false 39 | ``` 40 | 41 | There's a ton operators you can do with test. Here are some examples: 42 | 43 | ```bash 44 | test 15 -eq 15 # 0 45 | test brian = brian # 0 46 | test brian != brian # 1 47 | test 15 -gt 10 # 0 gt means greater than 48 | test 15 -le 10 # 1 le means less than or equal to 49 | test -e ~/some-file.txt # tests to see if a file exists 50 | test -w ~/some-file.txt # tests to see if a file exists and you can write to it 51 | ``` 52 | 53 | I'll stop here but you get the point. There are a lot. Again, check out `man test` to see all your options. So you can translate these into if statements like this: 54 | 55 | ```bash 56 | if [ -w ~/some-file.txt ]; then 57 | echo "hooray! I can write to this file" 58 | fi 59 | ``` 60 | 61 | The `[]` take the place of the test command. 62 | 63 | # else and elif 64 | 65 | What about else and else if? Create a new file called ten.sh. Put this in there 66 | 67 | ```bash 68 | if [ $1 -gt 10 ]; then 69 | echo "greater than 10" 70 | elif [ $1 -lt 10 ]; then 71 | echo "less than 10" 72 | else 73 | echo "equals 10" 74 | fi 75 | ``` 76 | 77 | This will let the user give an argument of a number and it will tell you if it's greater than, equal to, or less than 10 using conditionals. 78 | 79 | ## Case Statements 80 | 81 | Let's make one more quick program. Make a file called faces.sh. Put this in flag.sh 82 | 83 | ```bash 84 | case $1 in 85 | "smile") 86 | echo ":)" 87 | ;; 88 | "sad") 89 | echo ":(" 90 | ;; 91 | "laugh") 92 | echo ":D" 93 | ;; 94 | "sword") 95 | echo "o()xxx[{::::::::::::::>" 96 | ;; 97 | "surprise") 98 | echo "O_O" 99 | ;; 100 | *) 101 | echo "I don't know that one yet!" 102 | ;; 103 | esac 104 | ``` 105 | 106 | There's more fanciness you can accomplish with switch statements but I'll let you get more into it if you want to. 107 | -------------------------------------------------------------------------------- /lessons/cron.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/cron" 3 | title: "cron" 4 | order: "10A" 5 | section: "Last Thoughts" 6 | description: "Ever had a task that needs to be done every day? Linux has a feature called cron that will run tasks on a schedule. Brian goes over how to set these up." 7 | --- 8 | 9 | Ever had a task that needs to be done every day? Linux has a feature called cron that will run tasks on a schedule. 10 | 11 | There are two ways to accomplish this, an easy way to remember and a slightly less easy way. 12 | 13 | ## cron folders 14 | 15 | Any script you put in any of the following will be run on a schedule: 16 | 17 | - /etc/cron.daily 18 | - /etc/cron.hourly 19 | - /etc/cron.monthly 20 | - /etc/cron.weekly 21 | 22 | Just make sure they have executable privileges. `sudo chmod +x ` will do what you need it to do. Anything in here will be run as root. 23 | 24 | ## crontab 25 | 26 | If you need a more defined schedule (like every five minutes, every other Thursday, every six months, etc.) then you can use the classic way, crontab. With crontab you can define a cron schedule to execute your scripts. Let's say we want to make a new file in `~/cronfiles` every two minutes. 27 | 28 | First, let's make the script. In your home directory, create `make-new-file` and put this in there. 29 | 30 | ```bash 31 | mkdir -p ~/temp-files 32 | cd ~/temp-files 33 | touch file-$(date +%s).txt 34 | ``` 35 | 36 | `date +%s` gives you the epoch timestamp, or how many seconds have elapsed since Jan 1, 1970. 37 | 38 | Now, if you do `crontab -e` it will run this as well as root. In this case, we'd like it to run as ubuntu. You can do that by doing `crontab -u ubuntu -e`. The first time it will ask you what editor you prefer to use to edit your crontab. I used vim. 39 | 40 | So the comments in the file it explains fairly well what to do but let's go over it. One job will look like this 41 | 42 | ```bash 43 | * * * * * 44 | ``` 45 | 46 | The above five stars would run every minute. Each of those stars represents a frequency. They represent as follows: 47 | 48 | ` ` 49 | 50 | The stars mean "every", hence why five stars runs every minute, So if we wanted to command once an hour on the fifth minute, we could do this: 51 | 52 | ```bash 53 | 5 * * * * 54 | ``` 55 | 56 | If we wanted it to run every half hour on Sundays, we could do: 57 | 58 | ```bash 59 | */30 * * * 0 60 | 0,30 * * * 0 61 | # both equivalent 62 | ``` 63 | 64 | And so on and so forth. You can also use one of the special strings in here too: 65 | 66 | ```bash 67 | @daily 68 | @reboot # everytime it starts up 69 | @weekly 70 | @yearly 71 | @monthly 72 | @annually 73 | ``` 74 | 75 | So yeah, like regex, I have to look this up every time. I rely a lot [crontab.guru][guru]. It helps me make sure I got it right. 76 | 77 | So let's do it for our program. Run `crontab -u ubuntu -e`. Then once you've done that watch your new directory to start populating with files every two minutes. 78 | 79 | That's it for cron jobs! Be sure to delete the one we created or it will continue forever and fill up temp files! 80 | 81 | [guru]: https://crontab.guru/ 82 | -------------------------------------------------------------------------------- /lessons/curl.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/curl" 3 | title: "curl" 4 | order: "7D" 5 | section: "Networking and the Internet" 6 | description: "Frequently developers will want to interact with the network. Linux provides two command lines that are very well poised to help a developer out. Brian talks about two of the most popular, wget and curl." 7 | --- 8 | 9 | While wget works more like cp, curl works more like a normal Linux program. It works more like cat where it operates on input and output streams. Because of this it is a more useful tool to have in your arsenal because you can plug it into other programs. 10 | 11 | So let's do some examples of how curl can be used to do testing against API servers. I frequently use curl for this (as opposed to something like Postman or Insomniac which are both great too.) First thing we're going to do is run a static file server from our home directory (on primary, fyi, we're done using the secondary machine.) Run this: 12 | 13 | ```bash 14 | cd ~ 15 | python3 -m http.server 8000 --bind 0.0.0.0 16 | ``` 17 | 18 | This uses Python to run a little HTTP server locally. It, like `php -S`, NGINX, Apache, or any of those things of the similar nature will serve files from your local system. So if I make a request to http://localhost:8000/brian.txt I will get served whatever the file contents of brian.txt is from my home directory. Why did we choose Python here? Because Python ships with Ubuntu whereas we'd have to install other things. If you want to see what it's serving, use `ifconfig` to find your IP address and open `http://:8000` in your browser to see what it's serving. 19 | 20 | Okay, so now open a second shell inside primary. Easiest way is again probably to open Terminal.app/PowerShell and run `multipass shell primary` and it should hand you a new shell. Have the two shells side-by-side so you can see the output of both. Run this: 21 | 22 | ```bash 23 | curl http://localhost:8000 24 | ``` 25 | 26 | You'll get a bunch of HTML back from the server which is the same HTML that was served to your browser. Notice in your terminal that's running the HTTP server that it's reporting the HTTP requests, the path, the incoming IP and what [HTTP verb][http] was used. 27 | 28 | Okay, so let's run through a bunch of common things to do with curl really quick. Again, this is a deep pool. If you need to do anything with making HTTP requests (or FTP or really any network protocol) then there's a high chance that curl can do it for you. I'm just going to introduce you to how I mostly use it. 29 | 30 | ## Output 31 | 32 | First of all, since curl is stream based, you can absolutely `curl > output.txt`. This is its chief advantage over wget in my opinion. You can plug it into a greater chain of commands. You can also use `-o ` to redirect output to a file or just `-O` to redirect it to a file named by the same file name e.g. http://localhost:8000/brian.txt would go to brian.txt 33 | 34 | ## HTTP Verbs 35 | 36 | Something I'll frequently do to make sure an endpoint is working is `curl -I` (or `curl --head`). This will send a HEAD request instead of a GET request. HEAD requests just get the endpoint metadata and don't actually do a full request. This is a quick way to see if a server is ready to respond to a given request. Run `curl -I http://localhost:8000` and see what you get. Check the output from the server and see that it reports getting a HEAD request instead of a GET. 37 | 38 | Often you'll want to do other HTTP verbs as well like POST, PUT, DELETE, and PATCH. Of those, POST is by far the most common of those. Let's see how to do a POST. Run this: 39 | 40 | ```bash 41 | curl -X POST http://localhost:8000 42 | curl -d "this is the body being sent with the HTTP request" http://localhost:8000 43 | # both of these requests will fail because our static 44 | # file server doesn't know what to do with POST requests 45 | ``` 46 | 47 | The first one, `-X` allows you to specify what verb you want to use. In this case we used `POST`. In the second case, because we're using -d to send a POST body it implicitly sets the verb to POST as well. Again, both requests will fail because our server doesn't know what to do with POST requests. We expect that. 48 | 49 | By the same token, these will work too: 50 | 51 | ```bash 52 | curl -X PUT http://localhost:8000 53 | curl -X PATCH http://localhost:8000 54 | curl -X DELETE http://localhost:8000 55 | curl -X OPTIONS http://localhost:8000 56 | curl -X LOL_THIS_ISNT_REAL http://localhost:8000 57 | ``` 58 | 59 | ## Cookies 60 | 61 | Another very common thing to do is have to send [cookies][cookies] with your request as well. 62 | 63 | ```bash 64 | curl -b "name=brian" http://localhost:8000 65 | ``` 66 | 67 | This won't show up in the output of the HTTP server since it doesn't print cookies but yeah, this will send a cookie string along for the ride for you. 68 | 69 | Cookie jar files can be useful too. If you're making a lot of requests and need to send a lot of cookies, you can put all of those into a file and use `-c ` to use those as your cookies. 70 | 71 | ## Redirects 72 | 73 | Try running this: 74 | 75 | ```bash 76 | curl http://bit.ly/linux-cli 77 | ``` 78 | 79 | You'll notice you'll just a redirect notice. By default curl won't follow redirects. If you do `curl -L http://bit.ly/linux-cli` you'll tell curl to follow the redirect and you'll end up with the full course's website. 80 | 81 | ## Headers 82 | 83 | Another helpful thing is to be able to include headers. You'll use `-H` and you'll do one header per `-H` (meaning you'll need multiple `-H` to do multiple different headers) 84 | 85 | ```bash 86 | curl -H "'accept-language: en-US" -H "Authorization: Bearer 12345" http://localhost:8000 87 | ``` 88 | 89 | ## Edge / Chrome / Firefox curls 90 | 91 | One very cool feature of modern browsers is the ability to copy requests out of your network panel in your dev tools as curl requests and then be able to replay them from the command line. I do this all the time to properly formulate requests and get all the auth headers right. 92 | 93 | ![copying a URL out of Edge dev tools](./images/curl.png) 94 | 95 | ## curl | bash 96 | 97 | One last note here, a lot of tutorials or installation of tools will have you do a request of `curl | bash`. This will nab the contents of the URL off the network and pipe that directly into bash which will execute what's in the contents of the network request. This should make you uncomfortable. You're basically giving whoever controls that URL unlimited access to your computer. But hey! It's really convenient too: you just get and execute the file instantly. 98 | 99 | So what's my rule of thumb for doing that? A lot of people will tell you never, ever do it. I'll tell you _almost_ never, ever do it. There's a few things to keep in mind when you do it. 100 | 101 | - Always read the script you're about to invoke. You know enough now to see notice anything fishy. Be especially suspicious of them making more network requests or decoding base64 strings 102 | - Only do it from domains you trust. It's actually possible to detect a curl request as opposed to a browser request, meaning you can load the file in a browser and see something and then when you go to curl it they can serve you a different file. Basically means I only will do `curl | bash` from GitHub. 103 | - When in doubt just `curl url > file.sh` and then read the file. From there, `chmod 700 file.sh` and `. file.sh`. It's not that many more steps. 104 | 105 | [http]: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods 106 | [cookies]: https://en.wikipedia.org/wiki/HTTP_cookie 107 | [bash]: https://www.idontplaydarts.com/2016/04/detecting-curl-pipe-bash-server-side/ 108 | -------------------------------------------------------------------------------- /lessons/customize-your-shell.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/customize-your-shell" 3 | title: "Customize Your Shell" 4 | order: "10B" 5 | section: "Last Thoughts" 6 | description: "All engineers love to customize their tools to their absolute perfect liking. Their shells should be no different. Brian shows how to do a few things to make customize bash." 7 | --- 8 | 9 | All engineers love to customize their tools to their absolute perfect liking. Your shell and emulator should be no different. I'm going to show you a few things you can do to make your shell your own. 10 | 11 | ## Prompts 12 | 13 | Your prompt is the bit that shows up on every new line. By default it's something like `ubuntu@primary:~$`. You customize this by changing the environment variable `PS1`. If you say `PS1="hi "` you'll change you'll have hi at the beginning of every line. There's a myriad of things you can do hear and I'll let you discover those things yourself. 14 | 15 | More easily you can install someone else's. I'll show you quickly how to install one of the more well known ones, [powerline][powerline]. 16 | 17 | Run the following: `curl https://raw.githubusercontent.com/riobard/bash-powerline/master/bash-powerline.sh > ~/.bash-powerline.sh` 18 | 19 | Then add this line to your `~/.bashrc`: `source ~/.bash-powerline.sh`. Then run `source ~/.bashrc`. Voila! Now you have a very fancy prompt that will track git and all sorts of fun stuff for you. You can find other very cool prompts if you just search for bash prompt. 20 | 21 | ## Colors 22 | 23 | Multipass ships with nice colors, particularly for `ls` which is not colored by default, but sometimes you do have to set them yourself. 24 | 25 | In general there's a very rich language to color that doesn't suit us to get into but it just involves strings of characters that represent colors. A good example is as follows: 26 | 27 | ``` 28 | echo -e "This is how you make text \e[32mgreen" 29 | ``` 30 | 31 | The `-e` means looks for escapes (the `\` stuff.) Otherwise it'll ignore them. 32 | 33 | Mostly just wanted you to be aware that they exist if you need them. 34 | 35 | ## Change Your Caps Lock Key 36 | 37 | Just a minor suggestion for you all. In the terminal, you use CTRL a lot, you may consider remapping your caps lock from being caps lock to being CTRL. It makes all the combinations of buttons you do much easier. 38 | 39 | If you're an aspiring vim developer, you could make it Esc too. Both are good options. For macOS, you can do it from the keyboard settings menu. For Windows, download [PowerToys][pt] and use KeyboardManager. 40 | 41 | ## awesome-bash 42 | 43 | Lastly, [here's a great list of cool things for bash][awesome]. Definitely have a look around and you'll find all sorts of cool things bash can do! 44 | 45 | [powerline]: https://github.com/riobard/bash-powerline 46 | [bash]: https://github.com/awesome-lists/awesome-bash 47 | [pt]: https://github.com/microsoft/PowerToys#keyboard-manager 48 | -------------------------------------------------------------------------------- /lessons/environments.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/environments" 3 | title: "Environments" 4 | order: "6A" 5 | section: "Environments and Processes" 6 | description: "The environment of a Linux process is key to how it functions. In this section Brian goes over what that means, how to set up your environment, and how to manage it." 7 | --- 8 | 9 | Whether or not you realize it, your current session of your shell has a bunch of variables set. Most are just set by the OS, some by Multipass (or whatever you're using to run your computer), some by various programs, and some by you. 10 | 11 | Go ahead and run `printenv` to see what variable have been set. 12 | 13 | You'll probably see a super long list of environmental variables. Various programs will refer to these to modify how they work. And what's great you can modify these, either permanently, just for this session, or just for one command. 14 | 15 | So how do we use one? Well, let's give it a shot. Run: 16 | 17 | ```bash 18 | echo hello my name is $USER 19 | ``` 20 | 21 | You should see `hello my name is ubuntu`. That `$USER` signifies to bash "hey, replace this with a variable. So what if we wanted to change that USER just for one command? Try this: 22 | 23 | ```bash 24 | USER=brian echo hello my name is $USER # hello my name is brian 25 | echo hello my name is $USER # hello my name is ubuntu 26 | ``` 27 | 28 | As you can see, we add that little `VARIABLE=value` part at the first part of a command to temporarily modify the variables. 29 | 30 | ## Per Session 31 | 32 | So what if we want to modify a variable for a whole session (until you close _this_ open session of bash; if you open another tab of bash, even while this one is still running, it is a different session): 33 | 34 | ```bash 35 | echo $GREETING # nothing 36 | GREETING=hello 37 | echo $GREETING # hello 38 | ``` 39 | 40 | Again, once we close this window, GREETING goes away. 41 | 42 | ## Permanent 43 | 44 | So what if we want to last forever? There are a few options but really only one is recommend. 45 | 46 | The first is editing `/etc/environment`. This will modify _every_ user's environment so it's often not what you want. Each line in that environment file's format should be `VARIABLE=value` with one per line. 47 | 48 | Similar with `/etc/profile` and `/etc/bashrc` except with these you can actually invoke scripts within them. Again, this is system-wide and not usually what you want. 49 | 50 | ## .bashrc and .bash_profile 51 | 52 | This is always a point of confusion to me and I have to look it up every time so if that happens to you too don't worry. 53 | 54 | In your home directory, there are two files, `.bashrc` and `.bash_profile`. These are the files you need to configure and customize your bash shell. You can set things like telling Node.js you're in development mode, set up git how you want to, customize colors, set path, or really anything you can write a bash command for. 55 | 56 | `.bash_profile` is only run on login shells. That is to say, it's only run once for each time you log in to your computer. It is _not_ run after that. `.bashrc` is run on every nonlogin shell, so it's run on every tab of bash you start up. Typically what you want is to run your customizations on every shell so you actually just want to modify `.bashrc` and leave `.bash_profile` alone. Actually, what I'd suggest you do is go put this in your `.bash_profile`: 57 | 58 | ```bash 59 | if [ -f ~/.bashrc ]; then 60 | source ~/.bashrc 61 | fi 62 | ``` 63 | 64 | That way your `.bashrc` is _always_ run. And after you put this in there you can just forget `.bash_profile` exists and always just modify `.bashrc`. 65 | 66 | Okay, so now to have variables that affect all shells, you just put a line in there that says: 67 | 68 | ```bash 69 | export VARIABLE=value 70 | ``` 71 | 72 | and now it will survive when you log out. Just FYI, if you want that variable to affect _this_ shell, you'll have to do a `. ~/.bashrc` so that it will reload your .bashrc. The `.` means execute in this context. You also could say `source ~/.bashrc` and that would work too. 73 | -------------------------------------------------------------------------------- /lessons/errata.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/errata" 3 | title: "Errata" 4 | order: "10D" 5 | section: "Last Thoughts" 6 | description: "Inevitably things get messed up when teaching a course. Notes will be left here on what's wrong in the video." 7 | --- 8 | 9 | Inevitably things get messed up when teaching a course. Notes will be left here on what's wrong in the video. 10 | -------------------------------------------------------------------------------- /lessons/images/FrontendMastersLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/FrontendMastersLogo.png -------------------------------------------------------------------------------- /lessons/images/brian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/brian.jpg -------------------------------------------------------------------------------- /lessons/images/curl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/curl.png -------------------------------------------------------------------------------- /lessons/images/incident.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/incident.png -------------------------------------------------------------------------------- /lessons/images/linux_kernel_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/linux_kernel_map.png -------------------------------------------------------------------------------- /lessons/images/linux_timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/linux_timeline.png -------------------------------------------------------------------------------- /lessons/images/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lessons/images/lolcat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/lolcat.png -------------------------------------------------------------------------------- /lessons/images/multipass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/multipass.png -------------------------------------------------------------------------------- /lessons/images/nano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/nano.png -------------------------------------------------------------------------------- /lessons/images/penguin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/penguin.png -------------------------------------------------------------------------------- /lessons/images/real_programmers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/real_programmers.png -------------------------------------------------------------------------------- /lessons/images/sandwich.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/sandwich.png -------------------------------------------------------------------------------- /lessons/images/sudo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/sudo.jpg -------------------------------------------------------------------------------- /lessons/images/up-and-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/up-and-running.png -------------------------------------------------------------------------------- /lessons/images/vim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/lessons/images/vim.png -------------------------------------------------------------------------------- /lessons/interacting-with-files.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/interacting-with-files" 3 | title: "Interacting with Files" 4 | order: "5A" 5 | section: "Files, Pipes, and Permissions" 6 | description: "How do you interact with files in the command line? Brian goes over the essential programs for inteacting with files in Linux." 7 | --- 8 | 9 | A core concept of computing in general is files but in particular when it comes to navigating a command line. In this section we're going to go over some of the core programs you'll want to know so you can interact with files in Linux. 10 | 11 | # less 12 | 13 | Whereas we looked at file editors in the previous sections like nano and vim, less is a program for reading files. If you type `less textfile.txt`, it'll toss you into a reader mode of that file. Like vim, less is fairly robust program with lots of features and shortcuts that I don't know! The most important one for you to know is that if you hit `q` you'll quit less. Another useful keystroke is typing a number then hitting enter to head to that line. 14 | 15 | Another useful feature is you can type `/` and then a search term and it'll search for that. Type `n` to get the next match for that and `N` for the previous match. Note this works in vim too and that's the point; the shortcuts are meant to mimic vim to some degree. Hitting space will page down and b will page back up. 16 | 17 | Something that confuses a lot of people is there is another command called more. Indeed the tag line of less is "opposite of more". more is the predecessor of less and you can safely never use it since less is better. more was a much simpler and earlier program that lacked a lot of the features of less. You may run across some systems that only have more but that's rare. You can just always use less. There are also other variations of less like most but those generally don't ship with Linux by default. 18 | 19 | # man 20 | 21 | The reason that I chose to wait this long to introduce you to man is because it uses less to work! So everything you just learned with less applies to man. If you run `man less` it will show you the **man**ual for less. It's usually very exhaustive and thus can be a bit much to get through. Normally `--help` is a bit more succint so I usually try that first. But just about every command should come with a man you can look at. 22 | 23 | # cat 24 | 25 | Similar to less but all `cat` does is read the entire file and output it. So it doesn't paginate or anything fancy that like, it just reads it and outputs it to the standard output (we'll go over later what that actually means.) 26 | 27 | For something like textfile.txt where I know it's super short I'll just `cat textfile.txt` instead of using less. less is more useful when it's a long file. 28 | 29 | cat is short for con**cat**enate because it concatenates the file to the standard output. 30 | 31 | # head / tail 32 | 33 | These two are very descriptive. Head will read the first lines of a file and out put them and tail will read the last lines of a file and output them. By default both will output 10 lines but you can adjust that. 34 | 35 | Go ahead and `vim textfile.txt` and add 15 or so lines of text of whatever you want. Now run `head textfile.txt` to see the first ten lines. Now try `tail textfile.txt`. Now try `tail -n 3 textfile.txt` to just see three lines. This is often useful for looking at logs. 36 | 37 | A very useful trick is to `tail -f textfile.txt`. Notice it doesn't exit. Now it will update every time the file updates. This is useful if you're waiting for a file to change and you want to see it in real time (`-f` is for follow). So open another terminal window (Multipass will let you open another shell) and run the following `echo hi >> ~/textfile.txt`. You should see that appear in the other window running `tail -f textfile.txt`. We'll go over the `>>` in a little bit, but it just appends the output of echo on that file. This works for head too; the two programs work the same. 38 | 39 | # mkdir 40 | 41 | mkdir makes a new directory/folder. Run `mkdir my-new-folder` to see a new folder. Run `cd my-new-folder` to change directory into it. 42 | 43 | Another useful thing is the `-p` (for parents) flag. Run `mkdir -p a/lot/of/folders` and it will create all those folders as necessary. 44 | 45 | # touch 46 | 47 | Touch create a new, empty file. If I say `touch new-file.txt` it'll create a new file called new-file.txt right where I am. If new-file.txt already exists then it just changes the last modified and last accessed time. This can be useful in a variety of scripting contexts where changing a file's modified time signals that something is supposed to happen. Most of the time I just use it to create new files. 48 | 49 | # rm 50 | 51 | Remove a file! Be very careful, this program has got no chill. You tell it delete it everything and it will oblige you. 52 | 53 | If you say `rm new-file.txt` it will remove the one file. If you say `rm my-new-folder` it won't let you. You have to say `rm -r my-new-folder` to remove a directory. If my-new-folder has anything in it, it's going to make you confirm every single file that you want to delete it. If you're removing a very full file, this can get tedios so you can add `-f` to force everything through without confirmation. 54 | 55 | Again, exercise huge caution here, `rm -rf` is a bell that you can't unring. Once something has been `rm`'d, it doesn't go to the trash, it's just gone. 56 | 57 | **Never run this command**: `rm -rf /`. This is a famous command to run that will start deleting your whole system including the critical system files. It will start deleting everything until it deletes something so critical that system will never recover. I tell you so you're extra cautious to never do it. 58 | 59 | Lots of people recommend using [trash-cli][trash] instead. That way when you say `trash-put file.txt` it goes into a trash folder which can be recovered for some period before it gets deleted. This is a good idea that I constantly forget to do. trash-cli isn't installed by default and I'll show you later how to install new packages. 60 | 61 | # cp 62 | 63 | cp is short for copy and does just that. If you want copy a file you run `cp source-file.txt destination-file.txt`. You can also cp a file into a directory and implicitly keep the name of the original file by saying `cp source-file.txt my-new-folder/` and you'll have a file called source-file.txt inside of my-new-folder (the trailing slash is optional, just wanted to make sure you understood my-new-folder is a directory.) 64 | 65 | If you want to copy a whole folder and everything in it, use `cp -R source-directory destination-directory` to recursively copy everything from one place to the other. 66 | 67 | # mv 68 | 69 | mv stands for move. This how you move a file from one place to another, or how you rename a file (which is still moving it in some sense.) Try running `touch file.txt` then `mv file.txt new-name.txt`. 70 | 71 | Unlike cp, with mv you don't to do anything special to move a folder. Just do `mv folder-name new-folder-name` and it all works. 72 | 73 | # tar 74 | 75 | tar is one of the commands I always have to look up because I don't use it enough to remember all of its myriad flags. tar is short for tape archive and it initially used to prepare files to be backed up to a magnetic tape archive but it became useful to just group together files in single files as a tarball (like a zip file.) 76 | 77 | Let's say we wanted to put three files and a folder into a single tarball. Run the following 78 | 79 | ```bash 80 | mkdir folder1 81 | touch file1.txt file2.txt folder1/file3.txt 82 | tar -cf archive.tar file1.txt file2.txt folder1 83 | ls -lsah 84 | ``` 85 | 86 | You should now see a file called archive.tar. This is a single file that contains the above files. You should ship this off to your friend and they'd have the same three files with that directory when they un-tar'd it. 87 | 88 | However, this archive isn't compressed. It's literally just the files stuck together. Normally we'd want to compress this as well and tar makes it really easy to. If you just tack on the `-z` flag, it'll automatically compress it. So try this 89 | 90 | ```bash 91 | tar -zcf archive.tar.gz file1.txt file2.txt folder1 92 | ls -lsah 93 | ``` 94 | 95 | Notice archive.tar.gz is significantly smaller than archive.tar. This is because it got run through gzip. 96 | 97 | So let's unpack one of these. We'll do the gzip'd one because 99.99% of the time it should be compressed. 98 | 99 | ```bash 100 | mkdir destination-folder 101 | tar -xzf archive.tar.gz -C destination-folder/ 102 | ``` 103 | 104 | Notice we swapped c for x in the flags. This is because we went from creating to extracting. And then the `-C` is just giving it a destination folder to extract it. You can leave that off but it'll just extract the archive where-ever you are. 105 | 106 | [trash]: https://github.com/andreafrancia/trash-cli 107 | -------------------------------------------------------------------------------- /lessons/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/intro" 3 | title: "Introduction" 4 | order: "1A" 5 | section: "Welcome" 6 | description: "this is the description that will show up in social shares" 7 | --- 8 | 9 | Hello and welcome to the the Complete Intro to Linux and the CLI! 10 | 11 | ![Cute drawing of gentoo penguin](./images/penguin.png) 12 | 13 | This is an introduction on how to use the command line and in the process you will be learning Linux too. As an engineer, I use the command line not only daily but hourly. It's a constant companion in terms of getting my work done and I wouldn't be nearly as effective as I am able to without a decent knowledge of how to use it. I decided to create this workshop to empower new users of the command line to be able become instantly effective. While I maintain everything in this workshop is entry-level beginner friendly and useful knowledge, you will find even many senior engineers don't know how to do many of these things. The command line is an ocean of possibilities and often it's difficult to know what you don't know about it (so you can know to learn it.) 14 | 15 | ## Art and Design 16 | 17 | The art on this course is **adorable**, isn't it? It's done by the very talented [Alice Brereton][alice] who I very much suggest you commission some art from, or at least give her a follow on the socials. She did all the art you see on the front page as well as the lovely gentoo penguin above. 18 | 19 | As you may know, the official mascot of Linux is a penguin. We decided to give this course a [gentoo penguin][wiki]. Gentoo penguins love to collect stones, hence all the little rock art around. There is also a distro of Linux called [Gentoo][gentoo] that we won't be focused on today too 😄 20 | 21 | ## Who Are You 22 | 23 | This course is anyone who has ever wanted to learn the command line for any reason. You can be learning your very first programming language or you could be an industry veteran of decades; I beleive the knowledge in this course will help anyone. Honestly, it was years in the field before I actually took the time to investigate how to use the command line better. I imagine many of you are in the same boat. 24 | 25 | A tiny bit of programming experience is helpful. If this is the first code you will ever have written there are some sections that could be challenging. But even then there's still a lot here for you. 26 | 27 | This course will also impart a decent amount of knowledge of Linux and specifically Ubuntu. Much of what is taught here is portable to other shells and operating systems, and certainly all of the principles are. However you will find many minor and major differences. That said, rest assured most of my knowledge was earned in zsh on macOS and it transferred neatly to Linux and bash. Much of this transfers to PowerShell and Windows too. 28 | 29 | ## What You Can Expect 30 | 31 | If you go through this class, you can reasonably expect to end up in a place being comfortable with the command line. That was my goal in writing this class: 32 | 33 | - Those who aren't comfortable with Linux and/or the command line would end up comfortable with the command line and Linux 34 | - Those who are comfortable will learn a bunch of tips and tricks as well as learn additional depth on things they already knew 35 | 36 | ## Contributing 37 | 38 | Find a typo or error? This course is open source! [File an issue or open a pull request][course]. 39 | 40 | ## Errata 41 | 42 | We're trying a new thing on this course! We're sticking an errata at the end so if we find anything that's amiss or wrong with the course, we'll leave a note in the errata. [See here][errata]. 43 | 44 | ## Who Am I 45 | 46 | ![Brian speaking at a conference](./images/brian.jpg) 47 | 48 | My name is Brian Holt and I, as of writing, work at Microsoft as a senior program manager. I specifically manage developer experience for JavaScript developers on Azure and work on Visual Studio Code. I've also done developer relations for Microsoft and been a JavaScript engineer at LinkedIn, Netflix, Reddit, and some other smaller startups. Suffice to say, I think a lot about code, developer tools, and making devs happy. 49 | 50 | When not working, you can find me being terrible at Overwatch, travelling the world, sampling the finest peatiest whiskies and hoppiest beers, sweating on a Peloton, or just hanging out with my wonderful wife and sassy dog. Currently I live in Seattle, Washington in the United States but I've lived in Salt Lake City, San Francisco, Milan, Torino, and a few other places too. 51 | 52 | While I have your attention too, I'd like to call out my three favorite charities: [AnnieCannons][ac], [The Last Mile][tlm], and [VetsWhoCode][vwc]. 53 | 54 | ## Special Thanks to Frontend Masters 55 | 56 | ![Frontend Masters](./images/FrontendMastersLogo.png) 57 | 58 | The people at [Frontend Masters][fem] really are my family. Thanks to Marc and his whole wonderful company to their kindness and diligent work. The reason this course exists is because of the hard work they do. And because of them I get to open source this course. The course materials here are licensed such that you can share them whomever you please, whether or not they're a Frontend Masters subscriber. The videos do require you to pay but I think that's worth the trade. 59 | 60 | I hope you all enjoy the course! This was an act of love from me and the Frontend Masters team. 61 | 62 | -- Brian 63 | 64 | ## PS 65 | 66 | Please catch up with me on social media! Do note I'm not the best at responding to private messages. 67 | 68 | - [Twitter][tw] 69 | - [LinkedIn][li] 70 | - [GitHub][gh] 71 | 72 | And if I could trouble you to [give this course a star][course], it would mean the world to me ⭐️ 73 | 74 | [tw]: https://twitter.com/holtbt 75 | [gh]: https://github.com/btholt 76 | [li]: https://linkedin.com/in/btholt 77 | [course]: https://github.com/btholt/complete-intro-to-linux-and-the-cli 78 | [tlm]: https://thelastmile.org/donate/ 79 | [ac]: https://anniecannons.org/invest 80 | [vwc]: https://vetswhocode.io/donate 81 | [fem]: https://www.frontendmasters.com 82 | [alice]: https://www.pickledalice.com/ 83 | [wiki]: https://en.wikipedia.org/wiki/Gentoo_penguin 84 | [gentoo]: https://www.gentoo.org/ 85 | [errata]: https://btholt.github.io/complete-intro-to-linux-and-the-cli/errata 86 | -------------------------------------------------------------------------------- /lessons/lets-run-linux.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/lets-run-linux" 3 | title: "Let's Run Linux" 4 | order: "2C" 5 | description: "Brian goes over how to get Linux running on Windows 10 and macOS computers with either VirtualBox or Multipass" 6 | section: "Linux" 7 | --- 8 | 9 | So, enough chit-chat, let's run Linux!! 10 | 11 | You have some options, so let's go through those. Which operating system are you using right now? If you're using a desktop running Linux of some variety, you're already set and you can skip this section unless you're curious how to get up and running on macOS and Windows. 12 | 13 | # Virtualization 14 | 15 | We're going to running our Linux through a process call virtualization. We'll be running a virtual machine which is frequently abbreviated as VMs. VMs are an operating system running within another operating system, called the host machine. The host machine will create a virtual environment with virtual acccess to its hardware to the VM. The VM will have no idea that it's not actually running on real hardware; all it can see is the resources that the host is providing it. 16 | 17 | So, at this point, I'll be giving you instructions on how to get a VM running on macOS and on Windows. I'll give you several options so you can do what's best fit for you. 18 | 19 | I'll recommend most people will want to do Multipass. 20 | 21 | # For either macOS or Windows: Multipass 22 | 23 | [Multipass][mp] is a great new tool from the folks at Canonical (who make Ubuntu). It's a super easy way to spin up and spin down little VMs to try things out. You can even spin up multiple and play with them together. I'd recommend this for most users of macOS and Windows since it just sort of works without a lot of effort and you don't have to install everything yourself. 24 | 25 | **If you are on Windows 10 Home** you need to install VirtualBox ([link here][vb]) too in addition to Multipass. Multipass will use VirtualBox if it can't use Microsoft Hyper-V (a feature only available in Windows 10 Pro.) If you are on macOS or Windows 10 Pro, you do not need VirtualBox. 26 | 27 | - [Here are the Windows 10 instructions][mp-windows] 28 | - [Here are the macOS instructions][mp-macos] 29 | 30 | Once you have Multipass installed, you should be able to run it and open a new shell. For Mac users, it'll drop a little orange icon in your command bard at the top. For Windows, it's in your system tray (typically the bottom right of your screen, look for a little orange-and-white logo.) 31 | 32 | ![Screenshot of logged in shell](./images/multipass.png) 33 | 34 | You should be here. It has you logged in as the user "ubuntu" who has passwordless root privileges (if you don't know what that means, you'll find out in a bit, just means you're an admin who doesn't need a password.) 35 | 36 | # For either macOS or Windows: VirtualBox 37 | 38 | Oracle makes a product called [VirtualBox][vb]. VirtualBox is a hosted hypervisor which is another way of saying that this is a program that allows you to run VMs. It can run Windows, Linux, macOS, and many other VMs but today all we care about is Linux. I've been using VirtualBox for years and it's a reliable product. It's not the fastest nor the most feature rich but dammit it works. 39 | 40 | What's annoying about going down this path is that you'll need to download VirtualBox and you'll need to download the Ubuntu Server installer as well and go through the whole process. It's possible, it just takes some time. [Here's the link to the Ubuntu installer][ubuntu]. 41 | 42 | For creating the VM, just create a new Ubuntu 64 bit VM with the all default options. When you go to start it for the first time, it'll ask you to choose a boot media file. Point it at the Ubuntu 18.04 .iso file you downloaded. From here, just follow the instructions to install Ubuntu. Give it a username and password. This doesn't need to be super secure so just it a username and password you can remember. For everything else, just follow the menus and give the default responses. You don't need to connect to GitHub or anything, nor do you need any additional packages installed. 43 | 44 | It will ask you to restart after you install so do that. Once done, you should be able to start your VM and log in to your new shell with the username and password you created. At this point, your screen shoud look something like this: 45 | 46 | ![Screenshot of logged in shell](./images/up-and-running.png) 47 | 48 | It bears mentioning that VirtualBox isn't the only option. [VMWare Fusion][vmware] and [Parallels][parallels] (macOS only) are two great options too. They just aren't free. 49 | 50 | # For Windows Users: WSL 51 | 52 | If you're a Windows 10 user, you can install and use WSL. That's what I do for my local development and if you plan on being a serious developer, I'd strongly recommend installing WSL2. It allows you to run Linux natively inside of Windows. It's a bit of a burden to set up still because it's still not available in everyone's stable Windows (coming soon, you need Windows version 2004!) so I won't walk you through it but I'll leave the doc here if you're keen on going down that path: 53 | 54 | [Docs for installing WSL2][wsl] 55 | 56 | # Wrap Up 57 | 58 | At this point, you should have a shell prompt ready to go so we can continue with the course. This was annoying but necessary! Let's keep going. 59 | 60 | [vb]: https://www.virtualbox.org/ 61 | [ubuntu]: https://ubuntu.com/download/server 62 | [mp]: https://multipass.run 63 | [mp-macos]: https://multipass.run/docs/installing-on-macos 64 | [mp-windows]: https://multipass.run/docs/installing-on-windows 65 | [wsl]: https://docs.microsoft.com/en-us/windows/wsl/install-win10#update-to-wsl-2 66 | [vmware]: https://www.vmware.com/products/fusion.html 67 | [parallels]: https://www.parallels.com/ 68 | -------------------------------------------------------------------------------- /lessons/loops.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/loops-and-arrays" 3 | title: "Loops and Arrays" 4 | order: "9D" 5 | section: "Shell Scripts" 6 | description: "To make any sort of complicated program you need loops and arrays. In this section Brian teaches the syntax for making arrays and looping over them." 7 | --- 8 | 9 | Any programming language needs a way to do repetitive tasks and bash is no different. It has several flavors of loops that should look familiar to anyone who has done programming before. 10 | 11 | You frequently also need groups of variables. Bash has this is as well with arrays and we'll go over how to use those. 12 | 13 | ## Arrays and For Loops 14 | 15 | Arrays can do a lot and are very flexible. For now we're just going to go over how to declare them and how to read from them. Make a new array.sh and put this in there: 16 | 17 | ```bash 18 | #!/bin/bash 19 | 20 | friends=(Kyle Marc Jem "Brian Holt" Sarah) 21 | 22 | echo My second friend is ${friends[1]} 23 | 24 | for friend in ${friends[*]} 25 | do 26 | echo friend: $friend 27 | done 28 | 29 | echo "I have ${#friends[*]} friends" 30 | ``` 31 | 32 | The `friends=(Kyle Marc Jem "Brian Holt" Sarah)` line is how to define an array. If it's just one word (e.g. Kyle or Marc in this case) then you don't need quotes. You'll see for "Brian Holt" I added quotes so it can capture the space too. 33 | 34 | You see `${friends[1]}` is how you access items in an array. You do need the `{}` in this case or else it'll consfuse bash with path expansion stuff. 35 | 36 | Then we do a loop. We need to do the `${friends[*]}` to access everything in the array. If you said `echo ${friends[*]}` it would print the whole array. 37 | 38 | Then we can loop with `do` to start and `done` to end it. 39 | 40 | Lastly if you want to see the length, you use `${#friends[*]}`. Sort of wild stuff but it works! 41 | 42 | ## While 43 | 44 | What if we wanted to make a program that wouldn't exit until you guessed the correct number? We can use a while loop together with read to make such a wonderfully annoying game. 45 | 46 | ```bash 47 | # let "NUM_TO_GUESS = ${RANDOM} % 10 + 1" 48 | NUM_TO_GUESS=$(( $RANDOM % 10 + 1 )) 49 | GUESSED_NUM=0 50 | 51 | echo "guess a number between 1 and 10" 52 | 53 | while [ $NUM_TO_GUESS -ne $GUESSED_NUM ] 54 | do 55 | read -p "your guess: " GUESSED_NUM 56 | done 57 | 58 | echo "you got it!" 59 | ``` 60 | 61 | Let's talk a brief moment about `let`. `let` allows you to do math. You feed it a string of math of some variety and it will evaluate it for you. The shortcut to doing that (similar to how `test` works with []) is the dollar sign with double parentheses. The two lines I have there are equivalent. 62 | 63 | `$RANDOM` is just a random number which we're using [modulo][mod] to get a random number between 1 and 10. 64 | 65 | Then the interesting part there is our while loop looks a lot like an if statement. And that's it! 66 | 67 | There are more types of loops and more interesting things you can do with them but we'll leave that to you. I generally have to look them every time I use them anyway, same with the array stuff. 68 | -------------------------------------------------------------------------------- /lessons/nano.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/nano" 3 | title: "nano" 4 | order: "4A" 5 | section: "Editors" 6 | description: "Brian discusses one of the most common and most available text editors for the command line, nano" 7 | --- 8 | 9 | I am not a command-line-text-editor person and never have been. I made one shot in 2013-ish to try to switch to vim and ended up broken and confused. However as a newly-minted CLI afficanado, it's important that you know how to do the most basic sorts of text editing on in a CLI since you can't always open things outside of the CLI, and sometimes the CLI will toss you into a text editor and you need to know how to get done what you need to get done. 10 | 11 | ![xkcd comic, saying that nano, vi, emacs, etc devs aren't real developers and you need to use butterflys to influence the outer atmosphere to direct cosmic rays to your harddrive to flip bits to be a real programmer](./images/real_programmers.png) 12 | 13 | Comic from xkcd by Randall Munroe, [link to comic here][xkcd]. 14 | 15 | This is a hot button topic for a lot of people and has some pretty distinct tribal lines. I'll just say they're all great tools and you should use Visual Studio Code. 😄 16 | 17 | We're going to go over two of the myriad of tools available. I chose these two specifically because they are the two you are most likely to have already installed and/or be thrown into accidentally. If you don't know how to use them, they can be pretty intimidating. I definitely only know how to do basic text editing and saving so I'm not going to be giving an in-depth treatise on them, just enough so they're not scary anymore. 18 | 19 | # nano 20 | 21 | [nano][nano] is an old open source text editor that itself was an evolution from a previous text editor called pico. Pico was the text editor of the command-line email client Pine that people grew to love so much that they used it for everything. Because Pine was licensed in such a way that Debian wouldn't include it with its distro, Chris Allegretta re-implemented under the name TIP (**T**ip **I**sn't **P**ico, computer scientists love [recursive acronyms][acronyms]) it eventually was renamed to nano. 22 | 23 | Due its tiny size, light weight, and permissive license, nano is included on just about every Linux/Unix-like OS and is frequently the default text editor, even on tiny little embedded devices where even vim is too much. As such, it's a good tool to have your tool belt if you need to do some light text editing. 24 | 25 | So let's get a brief tour of what you can do in nano. 26 | 27 | Make sure you're in your home directory. If not, type `cd ~` to get there. Type `nano textfile.txt`. This will create a new file called `textfile.txt` in the directory in your folder. Type something in there. I put "Hi, this is Brian. You're in a text file." Once you've written what you want to, take a look at the bottom bar and you'll see a bunch of available actions. 28 | 29 | ![bottom shortcuts for nano](./images/nano.png) 30 | 31 | The `^` represents CTRL. So if you want to "get help", you'll hit CTRL + G. The `M-` character represents the Meta key which keyboards don't have anymore. Given that, terminals have had to work around that. If you're on Windows, that key will be the Alt key. If you're on macOS, unfortunately the Option key has other uses already (making alternative characters like ¢∞§ etc) so you have to use Esc (weird, I know.) As a macOS user, I just deal with this because it's really only nano where it's awkward. There is a way to make your terminal use Option if you feel strongly about it but I don't. I really only use nano when I have to. 32 | 33 | Okay so here we are. We want to save our file. If you see at the bottom `^O` is "Write Out" which in reality just means save. You'll find in these older editors they use the term buffer liberally. What a buffer is that what you've written to that file before you save isn't actually saved in the file which means it's being held somewhere else. That "somewhere else" is the buffer which is just space in memory. 34 | 35 | So hit CTRL + O. It'll make sure you don't want to save it somewhere else and a few other options. We should be good with it so just hit enter. Now that we've completed what we wanted to do, hit CTRL + X to exit nano entirely. If you wanted to open the file again, you'd hit `nano textfile.txt`. 36 | 37 | nano can obviously do significantly more than what I've shown you but any time I want to do "significantly more" I'll figure out how to use VSCode instead so I don't invest any more into nano or vim than that. 38 | 39 | [xkcd]: https://xkcd.com/378/ 40 | [nano]: https://www.nano-editor.org/dist/latest/faq.html#1.1 41 | [acronyms]: https://en.wikipedia.org/wiki/Recursive_acronym 42 | -------------------------------------------------------------------------------- /lessons/process-operators.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/process-operators" 3 | title: "Exit Codes, Process Operators, and Subcommands" 4 | order: "6D" 5 | section: "Environments and Processes" 6 | description: "Need to run one command after another? Use process operators! Brian explains how to run sequence of commands and subcommands as well as exit codes" 7 | --- 8 | 9 | Before we jump too far into how to run commands in sequences, let's chat one second about exit codes. Whenever a process exits, it exits with an exit code. This exit code corresponds to if a process successfully completed whatever you told it to do. Sometimes this is a bit misleading because sometime programs are meant to be stopped before they complete (as some like `yes` will never actually complete by themselves). 10 | 11 | A program that successfully runs and exits by itself will have an exit code of 0. Try this: 12 | 13 | ```bash 14 | date # show current date, runs successfully 15 | echo $? # $? corresponds to the last exit code, in this case 0 16 | yes # hit CTRL+C to stop it 17 | echo $? # you stopped it so it exited with a non-zero code, 130 18 | ``` 19 | 20 | So what do all the codes mean? Well, it depends on the program and it's not super consistent. It can be any number from 0 to 256. But here are a few good ones that are common 21 | 22 | - 0: means it was successful. Anything other than 0 means it failed 23 | - 1: a good general catch-all "there was an error" 24 | - 2: a bash internal error, meaning you or the program tried to use bash in an incorrect way 25 | - 126: Either you don't have permission or the file isn't executable 26 | - 127: Command not found 27 | - 128: The exit command itself had a problem, usually that you provided a non-integer exit code to it 28 | - 130: You ended the program with CTRL+C 29 | - 137: You ended the program with SIGKILL 30 | - 255: Out-of-bounds, you tried to exit with a code larger than 255 31 | 32 | There are a few others but these are the most common ones you'll see. You'll see some programs use numbers like 5 to 100 to signify different ways the program ended but you can pretty safely ignore that. It's usually just important if it's 0 or not-0. 33 | 34 | Okay, so why is this important? It can be useful to see if a previous command succeeded or not, but it's also useful for running programs in a sequence using operations. 35 | 36 | So what if you need to run two processes in a row, one right after the other? Well, you have a few options. 37 | 38 | ## Run if first one succeeds 39 | 40 | You'll probably see this the most. Let's say I wanted to create a file, add the date to it, and then add my current uptime to it. (try runnning `uptime`, it just tells you how long your computer has been running.) 41 | 42 | ```bash 43 | touch status.txt && date >> status.txt && uptime >> status.txt 44 | cat status.txt 45 | ``` 46 | 47 | You can see it does all three commands right in a row. That's what the `&&` operator does. It runs from left to right (touch, date, then uptime). The `&&` operator will bail if any of those commands fails. Try this: 48 | 49 | ```bash 50 | date && cat not-real-file.txt && echo hi # the date will display but hi won't 51 | ``` 52 | 53 | Since `not-real-file.txt` doesn't exit, it bails and hi is never echoed. 54 | 55 | ## Run if first one fails 56 | 57 | There's also a `||` command that will run if the first one fails. 58 | 59 | ```bash 60 | false || echo hi # you'll see hi 61 | false && echo hi # you won't see hi 62 | ``` 63 | 64 | `false` is a command that just returns `1` (there is a `true` that always returns 0) In this case, you'll see hi the first time and not the second time. 65 | 66 | ## Always Run 67 | 68 | If you need _always_ run the second command, use a `;` instead of either && or ||. 69 | 70 | ```bash 71 | false ; true ; echo hey # you'll see hey 72 | ``` 73 | 74 | ## Subcommands 75 | 76 | Sometimes you need to invoke a command within a command. Luckily bash has you covered here with the ability to run subcommands. 77 | 78 | ```bash 79 | echo I think $(whoami) is a very cool user # I think ubuntu is very cool 80 | ``` 81 | 82 | The `$()` allows you to put bash commands inside of it that then you can use that output as part of an input to another command. In this case, we're using `whoami` to get your username to echo that affirming message out. Let's a more practical one. Let's say you wanted to make a job that you could run every day to output what your current uptime was. You could run this command 83 | 84 | ```bash 85 | echo $(date +%x) – $(uptime) >> log.txt 86 | ``` 87 | 88 | The `+%x` part is just saying what date of format you want, and I got that from reading `date --help`. So end printing something like 89 | 90 | ```txt 91 | 06/17/20 – 21:38:34 up 8:51, 1 user, load average: 0.00, 0.00, 0.00 92 | ``` 93 | 94 | There are far more useful logs to write but you can see here the power of subcommands. Note you can also use backticks like \` instead of $() but it's preferred to use the $() notation. Notably, you nest infinitely with \$(). For more reasons, [read here][reasons]. 95 | 96 | [reasons]: http://mywiki.wooledge.org/BashFAQ/082 97 | -------------------------------------------------------------------------------- /lessons/processes.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/processes" 3 | title: "Processes" 4 | order: "6B" 5 | section: "Environments and Processes" 6 | description: "One of the core components of Linux is managing processes. In this section Brian talks about what processes are, how to interact with them, and why they're important." 7 | --- 8 | 9 | At all times with Linux a certain amount of processes will be running. A process is any sort of command that's currently running. For example, if you have a shell open, you're running bash as a process. 10 | 11 | Go ahead and run `ps` and see what it outputs. For me the list is pretty short because it's showing just what me, ubuntu, is running which isn't much. ps stands for processes snaphshot. To prove my point, try the following. 12 | 13 | ```bash 14 | sleep 10 & 15 | ps 16 | ``` 17 | 18 | You'll notice now you'll have a sleep process running as well since you now own that process. So let's dissect a few things here. We'll get to what the `&` means in a bit (it means run this in the background.) `sleep ` just makes a process that waits for `` seconds and then exits. So `sleep 10` waits for ten seconds and then exits. 19 | 20 | Every process you run is assigned a process ID which everyone refers to as a pid. Every process is also owned by a user. Some processes will always be owned by root, others by whatever user you are, and others still. If you look at your ps output, you'll those random numbers next to what you're runnning. This is the pid. 21 | 22 | Sometimes you need to kill an in-flight process. You can do that by using `kill` and tell it what signal (same signals we were talking about earlier.) Let's try that. 23 | 24 | ```bash 25 | sleep 100 & 26 | ps # find the sleep pid 27 | kill -s SIGKILL 28 | ps # notice the process has been killed 29 | ``` 30 | 31 | Note you'll frequently see `kill -s SIGKILL` as `kill -9`. They mean the same thing. There are other numbers but I never remember what they are so I just use `-s` for things like `SIGTERM`. 32 | 33 | So what else is your computer running right now? Try `ps aux`. This will show you everything running from everyone, including all system processes. It should be substantially longer. You'll see a few processes running by you, many from root, and a few from others like systemd+, daemon, and others. This list can be overwhelming so I'll frequently feed this into grep to find things I'm looking for. Try this: 34 | 35 | ```bash 36 | ps aux | grep ps 37 | ``` 38 | 39 | You'll notice the list is pared down to just things have `ps` in them (including the `grep` command itself) 40 | 41 | ## Foreground and Background 42 | 43 | A process can either run in the foreground or the background. If something is running in the foreground, you'll see all the output and you will wait until it's finished. If it's running in the background, you can still see the output (unless you redirect it) but you can start doing other things. When you put the `&` at the end it means "I want this to run in the background" (and hence why we've been using it before.) 44 | 45 | Go ahead and try `sleep 2 &` to see this. After two or more seconds, hit enter again. Bash will let you know the job completed. 46 | 47 | Okay, so we see how to do that. What if we want to pause a currently running process? Try this: 48 | 49 | ```bash 50 | sleep 100 51 | # hit CTRL + Z 52 | jobs # notice process is stopped 53 | bg 1 # it's the first and only item in the list, the number refers to that 54 | jobs # notice process is running 55 | fg 1 # reattch to the process 56 | ``` 57 | 58 | Notice you can run `jobs` with a `-l` if you need the pid to kill it. 59 | 60 | This is a great way to start and stop scripts and in particular if you have a long running task that you want to complete but don't want to wait and want to do other things. Do be aware that if you close your terminal however that it will kill all your running jobs. You'll need to use something like [screen][screen] or [tmux][tmux] to accomplish that and those are beyond the scope of this course (I don't frequently use them so I don't teach them.) 61 | 62 | So when would you do this? Maybe if you needed to install something that could take a while or run a script that does some cleanup. You need it to run but you don't need to watch it. These are all great cases to send tasks to the background. 63 | 64 | [screen]: https://www.rackaid.com/blog/linux-screen-tutorial-and-how-to/ 65 | [tmux]: https://www.howtogeek.com/671422/how-to-use-tmux-on-linux-and-why-its-better-than-screen/ 66 | -------------------------------------------------------------------------------- /lessons/sftp.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/sftp" 3 | title: "SFTP" 4 | order: "7B" 5 | section: "Networking and the Internet" 6 | description: "Once you have set up ssh you automatically get sftp for free! sftp allows you to securely transfers files to and from a remote machine to your local machine." 7 | --- 8 | 9 | Sometimes you need to transfer files between two computers. This can take the form of either transferring files from you local computer to your remote server or from your remote computer back to your local computer. Before we had more mature continuous deployment tools like Azure Pipelines, Travis CI, or GitHub Actions, we often used a tool called ftp (file transfer protocol). While it worked and it was a relatively simple and straightforward of doing things, we moved onto to more reliable tools. However ftp evolved into **s**ecure ftp which we still use today. 10 | 11 | ## How to set up sftp 12 | 13 | Okay, buckle up. This is your biggest challenge yet. 14 | 15 | Just kidding, you're already done. One of the best things about sftp is that it works 100% over the same ways that ssh does so if you've set up ssh you've inherently set up sftp too (it possible to set up one and not the other but you have change some options.) This was a welcome departure from ftp which has its own setup process and ports that had to be managed. 16 | 17 | Okay so using the VMs we set up in the previous section, let's sftp into secondary from primary. The sftp interactive shell is similar to a less friendly and stripped down version of bash. The thing to keep in mind is you're in _two_ directories at the same time as opposed to normal bash when you're just in one. With sftp, you have a local context and a remote context. In order to run a local command, tack an `l` to the start of whatever command you're running, like `lls`, `lpwd`, or `lcd`. When you want to do it on the remote machine, just run the commands like normal, like `ls`, `pwd`, or `cd`. 18 | 19 | ```bash 20 | sftp brian@ 21 | lpwd # ubuntu's local home directory 22 | pwd # brian's remote home directory 23 | lls # the list of files in ubuntu's home directory 24 | ls # the list of files in brian's home directory 25 | help # see all the commands you can do 26 | ``` 27 | 28 | Feel free to navigate around. I tend to not spend too much time inside sftp because it's easier do everything in ssh except file transfers. The two key commands you need to know here are `get` and `put`. It's from the perspective of your local computer so in this case we're connecting from primary to secondary, so `get`ting something will download it from secondary and `put`ting someting will upload it. 29 | 30 | If you have some files already laying around go ahead and toy with it. This is a great thing to use with `tar` as well so you can bundle up packages of files before sending them to a different computer. 31 | 32 | So now we want to upload a file. But hey, you may not have a file to upload right now. It'd be great if we could run a quick command on our local computer. And you can! Just prefix it with `!` and you can quickly run a `touch` or a `tar`. 33 | 34 | ```bash 35 | !touch file-to-put.txt 36 | ``` 37 | 38 | Obviously I wouldn't encourage you to do a lot here; if you need to just disconnect and then reconnect later, but it's helpful for quick things you need to do. 39 | 40 | ```bash 41 | put file-to-put.txt putted-file.txt # second argument is optional, if you omit it'll just use the same name 42 | get putted-file.txt gotten-file.txt # same thing, second one is optional 43 | ``` 44 | 45 | Here we went through the very fruitful exercise of putting a file on a server, renaming it and then downloading it again. But now you can see how you can download and upload files. 46 | 47 | And that's it! sftp can do a few more things like make directories and chmod/chown stuff but I'll leave you to poke and prod that as you need to. 48 | -------------------------------------------------------------------------------- /lessons/signals-and-the-power-of-ctrl.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/signals-and-the-power-of-ctrl" 3 | title: "Signals and the Power of CTRL" 4 | order: "3C" 5 | section: "The CLI" 6 | description: "Brian talks about how and when to use CTRL when working with the command line: to send signals to bash and to accomplish shortcuts" 7 | --- 8 | 9 | CTRL is a very commonly used key when on the command line. It's used for shortcuts and also to send very specific signals to bash. Let's start with some of the short cuts. 10 | 11 | Actually, so much so, that I've remapped my caps lock to be CTRL since that's a lot easier for me to hit. You don't have to but you might think about it. Here's how to do that on macOS and Windows 12 | 13 | - [macOS][mac] 14 | - [Windows][win] 15 | 16 | # Shortcuts 17 | 18 | - CTRL + A – takes you to the beginning of the line 19 | - CTRL + E – takes you to the end of the line 20 | - CTRL + K – "yank" everything after the cursor 21 | - CTRL + U – "yank" everything before the cursor 22 | - CTRL + Y - "paste" (paste in quotes because it doesn't actually go into your system clipboard) everything you yanked 23 | - CTRL + L - clear the screen 24 | - CTRL + R – reverse search through history 25 | 26 | # Signals 27 | 28 | A signal is a notification that you send to a program. It's up to the program to understand what to do with that. It's like if your friend sent you a text message that said "come over." You (the program) are not obligated to do anything but the intent of the text is obvious, they (the user) want you to come over. The same applies here to programs. The good news is that generally everyone abides what's expected: if you send them a message to quit, they quit. 29 | 30 | ## CTRL + C – SIGINT 31 | 32 | If you hit CTRL + C while a program is running, you're telling it to **int**errupt what it's doing and stop. You'll use this constantly. One reason is some processes are designed to never quit until you send them a SIGINT to stop. A good example of that is the `yes` command. All `yes` does is spam the string "y" until you tell it to quit. A lazy programmer wrote it so it could automatically answer "yes" to all the prompts for interactive programs. (You can also say `yes n` or `yes whatever` and it'll spam whatever you want it to.) 33 | 34 | So go type `yes` into your terminal. You'll find yourself with an infinite wall of ever-spamming `y`s in front of you. To stop it, hit CTRL + C and it'll stop immediately. 35 | 36 | Another good use case is that you started running a command and you didn't mean to. You can send a SIGINT and start again. 37 | 38 | Again, some programs may not respect CTRL + C, and nearly all of them will take time to clean up after themselves when they do receive a SIGINT. 39 | 40 | ## CTRL + D – SIGQUIT 41 | 42 | Less useful but still good to know nonetheless is what CTRL + D does. Many programs won't respond to a SIGQUIT (some might, it's up to them) but bash itself will. If you're in a bash prompt and it want it to exit (like if you're remotely connected to a bash server for example), if you hit CTRL + D it'll tell the bash session to end. You also could close the window or just type `exit` and it'll exit too. 43 | 44 | ## SIGTERM 45 | 46 | There is no shortcut for SIGTERM but I wanted to make sure you knew it existed. If I use the `kill` program to kill another program, the way it does that is by sending a SIGTERM to the program. The difference is that if the program doesn't exit, kill will still shut down the process. We'll talk later about `kill` but know it's there. 47 | 48 | ## SIGKILL 49 | 50 | If you want a program to stop and stop **now**, you can do `kill -9` (or `kill -SIGKILL`) and it will send the SIGKILL which means to the program "don't clean up, just stop as soon as possible.) Again, we'll cover this in a bit. 51 | 52 | ## More signals 53 | 54 | There are many signals and I don't know what 10% of them do. If you run `kill -l` in your terminal, it'll show you all the signals your computer supports. Most of these are used for processes to communicate amongst each other or with the shell, like SIGALRM tell your emulator to make a beep. However only really the ones above you are the ones you care about. 55 | 56 | [mac]: https://support.apple.com/guide/mac-help/change-the-behavior-of-the-modifier-keys-mchlp1011/mac 57 | [win]: https://github.com/microsoft/PowerToys#keyboard-manager 58 | -------------------------------------------------------------------------------- /lessons/snaps.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/snaps" 3 | title: "Snaps" 4 | order: "8C" 5 | section: "Package Management" 6 | description: "The latest in Ubuntu is snaps, a new format for installing dependencies. Brian goes over what snaps are and whether you want to use them." 7 | --- 8 | 9 | Okay, so a bit of history here is necessary and I don't want to delve _too much_ into it. It has to do with how Linux programs are packaged and there's a decent amount of controversy and disagreement around the best way to do it is. 10 | 11 | Canonical a few years announced a new way of packaging app called snaps. Snaps are advantageous over what was there before (apt typically deals with debs) for a few reasons: 12 | 13 | - They're totally self contained. They package all their dependencies with them 14 | - They're sandboxed. They can't mess with your system 15 | - They can update by just downloading the difference between ther versions 16 | 17 | Debs are none of those but they've been around forever. Snaps can also run on other Linux distros like Fedora, Gentoo, and CentOS as long as you download the program that runs them (snapd.) There are two other chief competitors in this improved portable packaging format: AppImage and flatpak. Suffice to say, I'm not going to get into which is best because it's nuanced and I don't have a strong take on it, I just use Snap because it's made by Canonical, the same people who make Ubuntu. If you want more depth, [click here][snap-vs]. 18 | 19 | ## What is a Snap 20 | 21 | As stated above, it's just another way of packaging an app up and for the most part you don't really have to care. There's a few things that you do need to keep in mind however: 22 | 23 | - Snaps update automatically and you actually can't stop that from happening really. Debs update whenever you choose to do so 24 | - Snaps are safer. They're sandboxed and cannot break out of their home folders. Debs really can do whatever they want 25 | - Snaps are also how Ubuntu lets publish GUI apps like Visual Studio Code, Spotify, Firefox, etc. There's more than just command line tools. [See here for the store][store]. 26 | - Debs are reviewed before they're allowed onto the registry. They have to be or else renegade devs could publish anything they want. Snaps, due to their sandboxing, don't have to be. 27 | 28 | Which should you prefer? Often things like like [node][node] and [lolcat][lolcat] are available on both. I think you're fine with either. When I use a Linux desktop I 100% prefer snaps for desktop apps like Visual Studio Code, Spotify, and Firefox, but for commandline tools I tend to just follow whatever the instructions suggestion. You're good either way. 29 | 30 | Much of the same functionality of apt works the same with snap 31 | 32 | ```bash 33 | snap help 34 | 35 | sudo apt remove lolcat 36 | sudo snap install lolcat 37 | ls -lsah lolcat 38 | 39 | sudo apt remove nodejs 40 | snap info node 41 | sudo snap install --channel=14/stable --classic node 42 | # restart your shell by exiting and starting a new shell 43 | node -e "console.log('hi')" 44 | ``` 45 | 46 | The first one should be pretty straight forward. It will now be attached to the stable channel of lolcat so if they dev ever updates the stable channel you'll get that update for free. 47 | 48 | The second is a bit less straightforward. First of all, we attach ourselves to the 14/stable channel. We'll get all Node.js 14 stable updates automatically. That works well for me locally but it can be a bit scary to do that on a web server. In this case I'd want to have more control over the updates. 49 | 50 | We also specify `--classic`. This is basically saying "it's okay if this app isn't sandboxed." Node.js won't install otherwise. In these cases make sure you trust the provider of the snap. [NodeSource][nodesource] (who maintain the snap) are indeed worthy of your trust. Also you have to restart the shell so it can properly initialize itself. 51 | 52 | That's it for snaps! 53 | 54 | [snap-vs]: https://askubuntu.com/questions/866511/what-are-the-differences-between-snaps-appimage-flatpak-and-others 55 | [snap]: https://snapcraft.io/store 56 | [node]: https://snapcraft.io/node 57 | [lolcat]: https://snapcraft.io/lolcat 58 | [nodesource]: https://nodesource.com/ 59 | -------------------------------------------------------------------------------- /lessons/ssh.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/ssh" 3 | title: "SSH" 4 | order: "7A" 5 | section: "Networking and the Internet" 6 | description: "One of the most key things a developer needs to know how to do is connect to a remote server and run commands on it. In this section Brian shows you how to set up a second VM so you can remotely connect via ssh into it from the first one." 7 | --- 8 | 9 | One of the most key things you need to take away from this workshop is how to remotely connect to a server and run commands on it. This is one of the times you absolutely must know your way around bash or you'll be out of look because there's no other way how to do it. 10 | 11 | ## When would you do this 12 | 13 | One of the easiest things to do is to get a VM (virtual machine) up and running in the cloud. So many companies offer this like Azure, DigitalOcean, AWS, Linode, etc. A VM is literally just a Linux machine running somewhere in the cloud. Many times the only real way to administrate and run code on these servers is just to connect into a remote CLI session and run the code yourself. It's also very easy with your newly learned skills! Let's see how to do that. 14 | 15 | ## Get a second VM running 16 | 17 | I'm assuming here you're using Multipass. If not you'll have to figure out how to get a second VM running yourself. 18 | 19 | If you're running macOS, open a new terminal that's running locally for macOS. You can do that by right clicking on the Terminal icon in your dock and clicking New Window. 20 | 21 | If you're running Windows, open your start menu and search for PowerShell and open a window for that. 22 | 23 | If you're running Linux, just run this directly in a host context of your Linux machine, not inside your Multipass VM. 24 | 25 | Run this command (it's multipass specific so you don't really need to care what it does or how it works, it's just useful here.) 26 | 27 | ```bash 28 | multipass launch --name secondary 29 | ``` 30 | 31 | This will launch a second Linux VM named secondary (by default the first one was named primary.) This will take a second to start. Once it does you can type `multipass shell secondary`. You can also do it from the Multipass icon as well. This one will be identical to the first one but it's a whole separate VM so it won't have all the stuff from your first one in there. You'll also notice that when you log in it'll say `ubuntu@secondary` in your prompt instead of `ubuntu@primary`. 32 | 33 | On the secondary, let's make a new user. Run the following 34 | 35 | ```bash 36 | sudo useradd -s /bin/bash -m -g ubuntu brian 37 | sudo passwd brian # something simple, like asdf 38 | ``` 39 | 40 | This will create a new user with bash as their default shell (the `-s` part) with a premade home directory (the `-m` part), and they'll be apart of the ubuntu group (the `-g` part.) Now we'll make it so we can connect to the secondary as brian from the primary. 41 | 42 | ## SSH Keys 43 | 44 | The next thing we need to do is to create ssh keys for primary. The ssh key on primary is how it's going to identify itself to secondary. I'm not going to explain how ssh keys work (it's a lot of complicated math) but the basic gist is this: when you generate a new ssh key, you get two files, a public key and a private key. The public key is what you give to everyone else and is not a secret. You're basically giving them a key hole and telling them to install it on a door for you. The private key is just that, your private key. You will _never_ reveal this key to anyone. If anyone does get ahold of this key they can freely masquerade as you. This is the key to the key hole. If you do accidentally reveal your private key ever, you should immediately stop using it and make a new one. 45 | 46 | If you want to dig a bit deeper, check out the Wikipedia page on [Diffie-Hellman key exchange][dhke]. Fascinating history. This isn't the same as what ssh uses but rather the first sort of public key encryption that existed. 47 | 48 | So, on the primary, let's generate our public key. Run this: 49 | 50 | ```bash 51 | ssh-keygen -t rsa 52 | # hit enter to put the key files in the default place 53 | # hit enter to give an empty passphrase 54 | # hit enter again to confirm 55 | ``` 56 | 57 | Here we're generating a new random key. This key is essentially unguessable and therefore unless something unreal happens, is unhackable from a brute force perspective. We're telling it to put everything in the `~/.ssh` directory which is standard. Lastly we're electing to not give it a passphrase. In general it's a good idea to give it a passphrase so that anytime you use the SSH key you need to enter a passphrase (and frequently you can save a passkey to something like macOS's keychain) but in this case we're okay to skip it in the name of a demo. 58 | 59 | ## Connecting to secondary 60 | 61 | If you run `ls ~/.ssh` you'll at least see id_rsa (your private key) and id_rsa.pub (your public key.) These are ready to go to be used. We're going to use these allow ubuntu@primary to connect to brian@secondary. Run `cat ~/.ssh/id_rsa.pub` and copy the output onto your clipboard. 62 | 63 | Change now to your secondary machine. 64 | 65 | ```bash 66 | su brian 67 | mkdir ~/.ssh 68 | vi ~/.ssh/authorized_keys # paste in copied ssh id_rsa.pub from primary, write, and quit 69 | chmod 700 ~/.ssh 70 | chmod 600 ~/.ssh/authorized_keys 71 | ``` 72 | 73 | Note: you typically won't have to do this yourself. With someone like Azure or DigitalOcean, you'll give them your id_rsa.pub and they'll take care of making sure it gets into authorized_keys. You'll just have to generate it and give it to them. 74 | 75 | Lastly, we're going to need to give `ssh` an address to connect to. Just like you need an address to mail a letter to, you need an IP address to tell your computer where to connect to. Let's go grab that. Run the command `ifconfig`. This is going to dump out a bunch of addresses and hashes. 76 | 77 | You're looking for numbers like look this: `X.X.X.X`. 78 | 79 | For sure one of them will be 127.0.0.1. That's not it. That's called the loopback: a network address that refers to the same machine. Connecting to that would be like mailing a letter to yourself. Try `ping 127.0.0.1`. This will send little packets of data to that address and see if it responds. It'd be like looking in a mirror and saying "hey you there?" 80 | 81 | Ignore the mask and broadcast. Look for an inet one that looks like `192.168.64.3` or close to it. That's the one you're looking for. That's what the address of this secondary machine to broader network (in this case, this network is just local to your computer.) If you want to make sure it works, try `ping 192.168.64.3` and see if it responds with data. If it says it's unreachable you picked the wrong one. 82 | 83 | Okay! Now we're ready to connect from primary. Head back there and type this: 84 | 85 | ```bash 86 | ssh brian@ 87 | ``` 88 | 89 | You should connect! The primary machine is now connect via ssh to the secondary machine and now remotely running commands on it. Why is this a big deal? In this specific case it's not because we can just use Multipass to open a shell but it is a big deal because we can use this same process to connect to _any machine_. You can say `ssh brian@` and it works the same way! Now you can remotely connect to your server in the cloud or your Raspberry Pi in the other room. It works with any Linux machine you can connect to over the network. 90 | 91 | [dhke]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange 92 | -------------------------------------------------------------------------------- /lessons/streams-and-pipes.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/streams-and-pipes" 3 | title: "Streams and Pipes" 4 | order: "5C" 5 | section: "Files, Pipes, and Permissions" 6 | description: "Linux has an interesting concept called streams. The most common of these are stdout, stderr, and stdin. Brian goes over what streams are and how to pipe them together." 7 | --- 8 | 9 | Linux has an interesting concept where basically all input and output (which are text) are actually streams of data/text. Like plumbing pipes where you can connect and disconnect sections to redirect water to different places, so too can you connect and disconnect streams of data. 10 | 11 | # The Standard Streams 12 | 13 | There are three standard streams, stdin (said standard input or standard in,) stdout (said standard output or standard out,) and stderr (said standard error or standard err.) stdin is an input stream to a program and the other two are output streams. stdout for all non-error text, the normal output. stderr is just for error information. 14 | 15 | ## stdout 16 | 17 | stdout is where all normal output goes. If it's not caught or redirected, stdout by default goes to your terminal screen (as does stderr too.) A good example of that is our friend cat. cat take a file and concatenates it to the stdout. If you do `cat file1.txt` and don't redirect that stream somewhere else, it ends up at the terminal screen and you get the ouptut of the file. What if we wanted to redirect the output? We can! 18 | 19 | Try this. 20 | 21 | ```bash 22 | echo "this will get output to the file and not to stdout" 1> new-file.txt 23 | ``` 24 | 25 | The `1>` redirect stdout from heading to the terminal and into a file, new-file.txt. We don't see the output of echo; it's been redirected. So what if we wanted to do that to cat? 26 | 27 | ```bash 28 | cat new-file.txt 1> yet-new-file.txt 29 | ``` 30 | 31 | What do you think happened here? We concatenated new-file.txt to stdout and then redirected stdout to a file. So basically we did `cp` with more steps and concepts. But hey! Now you can see the power of piping stdout to different places. 32 | 33 | ## Replacing vs appending 34 | 35 | So far we've been replacing files with `1>`. What if we want to append? That is to say, instead of replacing the file's contents, we just want to add new stuff to the end? That's where `1>>` comes in (this will work with all streams, not just 1 / stdout.) 36 | 37 | ```bash 38 | ls -lsah 1> ls.txt 39 | ls -lsah 1>> ls.txt 40 | ``` 41 | 42 | What would you expect the output of ls.txt to be now? It's two outputs of `ls -lsah`. 43 | 44 | ## stderr 45 | 46 | So let's talk about the other output stream, stderr. While `1>` redirects stdout, `2>` redirect stderr. So if I say `ls -lsah 2> error-log.txt` what would you expect to happen? You'll see the normal output of stdout to the terminal since we didn't redirect it and it will create a new file called error-log.txt with nothing in it. 47 | 48 | Okay, so let's do something that causes an error then. Run `cat file-that-doesnt-exist.txt 2> error-log.txt`. So what happens here? Nothing gets output since nothing is concatenated to stdout (since that file doesn't exist) and `cat: file-that-doesnt-exist.txt: No such file or directory` gets output to error-log.txt. 49 | 50 | All the same things apply too with `2>` for replacing a file and `2>>` for appending. 51 | 52 | Note, so far everything we've done has had either error information or normal info and not both. Normally it'll have both. 53 | 54 | ## Redirecting both stderr and stdout 55 | 56 | Okay so now we want to redirect both stderr and stdout. Easy 57 | 58 | ```bash 59 | ls -lsah 1> stdout.txt 2> stderr.txt 60 | ``` 61 | 62 | This will redirect each of those streams to different files. 63 | 64 | We can have them go to the same file too! 65 | 66 | ```bash 67 | ls -lsah 1> ls.txt 2> ls.txt 68 | ``` 69 | 70 | Or, even more easily, 71 | 72 | ```bash 73 | ls -lsah > ls.txt 74 | ``` 75 | 76 | Yes, if you put no number there, it will output _both_ streams to the same file. Honestly this is what I normally do unless I'm keeping track of an error log separately (like I would on a production machine) but for just every day stuff, this is normally what I'd do. `>>` will work too for appending. 77 | 78 | ## /dev/null 79 | 80 | Sometimes you want to run a program and you don't really care what the output is; you just want to run the program. Say hello to `/dev/null` which is the programming equivalent of the infinite abyss. Anything that gets output to /dev/null is thrown away. Let's say you're running a program that's very noisy and you really only care if there's an error. 81 | 82 | ```bash 83 | ls -lsah 1> /dev/null # assume this is a very noisy program 84 | ``` 85 | 86 | This will run the command and only print the errors. Everything else gets chucked into the infinite abyss. Useful sometimes 87 | 88 | ## stdin 89 | 90 | Okay, so now we've talked exhaustively about the output streams, let's chat a minute about input streams. 91 | 92 | stderr and stdout direct the text from a program to a file. With stdin, we can direct the contents of a file into a program via the stdin. Try this 93 | 94 | ```bash 95 | cat < ls.txt 96 | ``` 97 | 98 | Now, again, not entirely useful, since `cat ls.txt` would have done the same thing. But let's say it's a very long file and we want to find one very specific line. We could do this: 99 | 100 | ```bash 101 | grep "error-log.txt" < ls.txt 102 | ``` 103 | 104 | We'll talk about the ins and outs of grep in a later chapter but for now it's enough to know it lets you find things in a text stream. In this case, we took the contents of `ls.txt` and connected that stream to grep which grep then looked for a line that contained "error-log.txt" in it. So that's what `<` does, it take a file and puts that into stdin so a program can use it. 105 | 106 | ## Using stdin and stdout 107 | 108 | What if we want to have both stdin and stdout and then throw away the errors? 109 | 110 | ```bash 111 | grep "error-log.txt" < ls.txt 1> ls2.txt 2> /dev/null 112 | ``` 113 | 114 | Just like that! Order isn't important. 115 | 116 | ## Why? 117 | 118 | Hopefully by now you understand how this works but you may be asking why? All these examples seem contrived and so far they have been. But when you start running commands yourself you'll find that a lot of the times you need to keep track of what happens. A good example is if I'm running a web server from a computer: I want the output from the server (like who logged in, anayltics, metrics, security stuff, etc.) to live in one place so I can keep track of the logs and I want the error logs to live in another place so I can debug successfully what's going on with my server. In this case, stderr and stdout are _very_ useful. What if I need to to input some secrets like passwords and cache keys to a server in order to start it up? stdin is definitely one way to do that. 119 | 120 | ## Pipes 121 | 122 | Okay so we've exhausted you can do with just files but what if we want to use the output of one program into another? Enter the pipe (sometimes called vertical bar,) `|`. This takes what one program outputs and puts it into the next one. This opens up a lot of possibilites. Let's redo that one we had above with grep using cat and |. 123 | 124 | ```bash 125 | cat ls.txt | grep "error-log.txt" 126 | ``` 127 | 128 | cat will concatentate ls.txt to stdout and then `|` will take the output of that and run that as stdin to grep. 129 | 130 | Let's try another using ps. We'll get to processes later but ps outputs all running processes. It's usually a very long list since Linux has a lot running all the time. Try running `ps aux` and see how long it is. It can be much longer too if you're running a server. Notice the last thing it outputs is the `ps aux` command itself that you used to find it. Let's use grep to find just that line and nothing else. Try this: 131 | 132 | ```bash 133 | ps aux | grep "ps aux" 134 | ``` 135 | 136 | This should output two lines, the `ps aux` call and the `grep` we're running to find that ps aux. A little self referential but the point here is that we're able to find just what we need and leave the rest behind. And we're doing that with the power of pipes. `ps aux` find all processes and outputs that to stdout. We then take that stdout and run that as the stdin to grep. grep then finds just the lines it needs and outputs just those to its stdout. At this point we don't have anything else redirecting output streams so it gets output to the terminal window. We absolutely could redirect that out to a file using `1>`. 137 | 138 | Let's a bit trickier one. If you do `rm -i *.txt`, it'll try to remove all files with .txt extensions. It'll all confirm with you on each one to say either y for yes or n for no. Try it and say "n" and hit enter for each one. Notice afterwards you won't have deleted anything. 139 | 140 | Lots of Linux programs function this way of answering y or n questions. Someone got sick of doing it and wrote a program to just answer `y` nonstop called `yes`. We looked at this before. But now let's yes it. Let's make it say n to all those questions. 141 | 142 | ```bash 143 | yes n | rm -i *.txt 144 | ``` 145 | 146 | The first command, `yes n` outputs infinite `n`s to stdout. `rm -i *.txt` uses those from stdin to answer `n` to every question it asks. Pretty cool, right? 147 | 148 | We'll use pipes a lot. By this we can use smaller commands like grep, cat, yes, and other to make higher level programs. We're using bash to program! Bash scripting. 149 | -------------------------------------------------------------------------------- /lessons/tips-and-tricks.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/common-tips-and-tricks" 3 | title: "Common Tips and Tricks" 4 | order: "3B" 5 | section: "The CLI" 6 | description: "Brian talks about the common tips and tricks of the command line like what tilda means, how to find commands you previously ran, and other things to make your life on the command line" 7 | --- 8 | 9 | This section will be a bit of a grab bag of various tips and tricks to make your life easier. I also need to teach this because I use them so frequently I don't even think about it! 10 | 11 | # Tilda 12 | 13 | One quick tip here is the `~`, called a tilda. On USA layouts of keyboards, it's on the same key as the backtick and to the left of the 1 key. The tilda in bash represents your user's home directory. If you type `cd ~` you'll go to your home directory. If you type `ls ~/snap` you'll list the the contents of `/home/ubuntu/snap`. 14 | 15 | # Slash 16 | 17 | Similar to the above, if you say `cd /`, the `/` means root. So you'd be at the most root directory of your entire project. It's the beginning of an absolute path, so if you said `cd /usr` you'd end up at the `usr` directory in the root directory. 18 | 19 | # Up and Down 20 | 21 | You will use this _constantly_. If you hit the up arrow, you'll populate the command line with the last command you ran. If you hit up again, you'll go to the one before that, and so on and so forth. If you hit down, you'll go back to a more recent command. This is super useful and I do it all the time. 22 | 23 | # Tab Completion 24 | 25 | Most shells have a relatively robust tab completion system. When I say "tab completion" I mean you start typing something and hit the tab key, the shell will do its best to figure out what you're trying type. An example would be if I'm in a directory with two files, index.html and package.json, and I start typing `cat i` and hit tab, it will know the only file starting with `i` is index.html and will autocomplete your line to `cat index.html`. Saves you a lot of typing. 26 | 27 | For another example, imagine you have two files in a folder, index.html and index.js. If you start typing `cat` and hit tab, it'll complete out to `cat index.` because that's as far it can get without assuming which file you want to open. If you hit tab again, it should show you your two options. If you then hit `j` and hit tab it'll complete out `cat index.js` for you. 28 | 29 | Some commands are smart enough to know what sort of thing you're looking for. If you have two files, saved.txt and something-else.txt, and a folder called src, if you type `cd s` and hit tab, you'll autocomplete `cd src` because the shell knows you're looking for a folder when you're using `cd`. 30 | 31 | Tab completion will always work with the file system. Some commands have tab completion too. Type `git de` and hit tab and it should complete to `git describe` for example. Admittedly I use this far less because I can never remember which commands have tab completion and which don't. The individual programs have to supply that to the shell for it to work. 32 | 33 | # Reverse Search 34 | 35 | Instead of having to hit up a bunch of times to find a command you ran forever ago (it keeps track of something like the past 10K commands you've run), you can CTRL+R to do a reverse search (reverse meaning starting with the most recent and working background to most recent.) 36 | 37 | Let's say I ran the command `echo "hello my friends"` last week and I wanted to find that command again and I only remember that it had something to do with "friends". I'd type CTRL+R and start typing "friends". If it was the most recent command that I had run with "friends" in it, it'd show up and I could hit enter and it'd run. If there was another command between now and again, I can hit CTRL+R again to look further back in the history. This is also super useful and something I do a lot. 38 | 39 | # .bash_history 40 | 41 | The previous two things are made possible by a file called `.bash_history`. This file is constantly being appended to when you run commands. You don't really need to ever really edit this file but I wanted you to be aware of where it was and what it does. It's always in your home (`~`) directory. If you're using another shell, it'll be called something else like `.zsh_history`. 42 | 43 | If you type `tail ~/.bash_history` you should see what the last few commands you've ran in your previous session of bash. It will only write to .bash_history once you've exited bash, it'll dump the whole session's commands into it. 44 | 45 | One reason I want you to be aware of it is that if you say something like `command --password=my_super_secret_password` that will live in your `.bash_history` file unless you delete it. That means if someone gets ahold of your computer, they could potentially nab passwords that way. Just something to keep in mind. You can also edit the `.bash_history` after you run a command like that to delete it and it'll be gone. 46 | 47 | # !! 48 | 49 | If you type `!!` in bash, it will replace the `!!` with whatever the last command you ran. So if you just type `!!` and enter, it'll run the last command you ran. If you run `sudo !!` it'll re-run the same command again but with `sudo` in front (we'll talk about sudo soon.) 50 | 51 | "!" is often pronounced "bang" when it comes to the command line. When I looked at why, I found this on [Wikipedia][wiki] 52 | 53 | > In the 1950s, secretarial dictation and typesetting manuals in America referred to the mark as "bang", perhaps from comic books where the ! appeared in dialogue balloons to represent a gun being fired, although the nickname probably emerged from letterpress printing. 54 | 55 | So, given that, you'll hear this frequently called "bang bang". 56 | 57 | # clear 58 | 59 | If your screen is too full, just type `clear` and enter and it'll put you back at the top. You can still scroll back to see old output. CTRL+L will work too, but to be honest I can never remember it so I just use `clear`. 60 | 61 | # Copy and paste on the CLI 62 | 63 | Let's talk a moment about copy and paste with regards to the command line. 64 | 65 | 1. If you're on Windows, it's a bit of a trick. CTRL+C and CTRL+V already mean something different to bash (they're signals, we'll talk about those shortly) so those don't work as you'd anticipate. You'll need to use `Shift+CTRL+C` and `Shift+CTRL+V`. Because macOS uses CMD+C and CMD+V for copy and paste and those don't mean anything to bash, nothing changes for them. 66 | 2. Be careful of what you copy and paste. If you copy something off a website, using JavaScript they can switch what you highlight with something more nefarious so that when you paste it, it doesn't do what you copied. So I could have copied `echo "this is harmless"` but it actually pastes `send_attacker_my_passwords`. Be careful that you trust where you're copying and pasting from (StackOverflow is fine!) 67 | 3. Along with the former point, the attacker can actually even include the return character to execute the command before you can even see what it is. Most emulators (like Windows Terminal and iTerm2) will warn you "hey, we found a return character in this paste, are you sure you meant to do this?" but you shouldn't rely on the emulator to save you. 68 | 4. In general it's just helpful to understand what you're doing. If you copy and paste something, make an effort to grasp what it's doing and how. 69 | 70 | [wiki]: https://en.wikipedia.org/wiki/Exclamation_mark#History 71 | -------------------------------------------------------------------------------- /lessons/users-groups-and-permissions.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/users-groups-and-permissions" 3 | title: "Users, Groups, and Permissions" 4 | order: "5D" 5 | section: "Files, Pipes, and Permissions" 6 | description: "Another core function of Linux is its security and permission model. This centers around the concepts of users, groups, and permissions. Brian explains what this means to a user of Linux." 7 | --- 8 | 9 | Linux is inherently a multi user system. You have an account (in our case, ubuntu is the name of the user by default for Multipass) but there are always multiple users of a Linux system. Many of the users of the system aren't even meant to be actual human users; many programs will create their own users and groups to keep themselves separate from userspace. 10 | 11 | ## Users 12 | 13 | Run `whoami` from your command line. If you're using Multipass, it will likely say "ubuntu". This is useful in case you're not sure who is running some program. A user is what you'd expect: a user of the system. The user will have access to various files and not others. This is what you'd call permissions. 14 | 15 | Let's see what users are already on your machine. Run `cat /etc/passwd` (notice it's passwd, not password). This will print out all of the currently registered users on your computer. Right now I have 20ish users on my system. You'll notice programs like man and mail have their own users to keep their permissions separate from yours. Why? Linux generally adheres to the principle of least power: we want programs to be given the least amount of power possible to complete their tasks. That way if they run amok, either accidentally or maliciously, the amount of damage they can cause is as minimal as possible. 16 | 17 | ## Superuser 18 | 19 | `ubuntu` is a user and can only do things that a normal user can do. For example, a user cannot create a new user. Try `useradd brian` (or change `brian` for whatever you want the name of the new user to be.) You 'll see something saying "Permission denied". This is because only _the_ superuser can add new users. So let's try that. Run `sudo su`. We'll talk about sudo in a sec but `su` is switch user. Now try running `whoami` again. It should say "root". The root user is the superuser. Now we have ultimate power: the superuser has no restrictions on what it can do. Try running `useradd brian` and you'll see you run it with no problem. 20 | 21 | What we did, `sudo su` is usually not what you want to do. When you do things as root, it means usually that only root in the future will be able to modify and delete files it makes. It also means that if you fat finger a command and accidentally type something wrong, you really can burn down the house. It's like using a flamethrower to start a grill: you can do it but there's a good shot you're taking the house down with you. 22 | 23 | To get out of being root, just hit CTRL+D or run `exit`. You should be back to being ubuntu. 24 | 25 | ## Sudo 26 | 27 | ![Sarah Drasner's dog, Sudo](./images/sudo.jpg) 28 | 29 | Sudo is [Sarah Drasner's _adorable_ dog][sarah] who I just love. If you haven't watched any of Sarah's courses they're **amazing**. 30 | 31 | Let's try deleting that brian user we added. Run `userdel brian`. It should tell you you can't again because of permissions. So let's run just one command as root. Use `sudo userdel brian`. `sudo` mean "switch user and do". If you don't tell it which user to switch to, it defaults to root (and 99.99% of the time it's what you meant to do.) This is great for things like this: ubuntu can't accomplish this so I have to use root. Instead of fully switching into root, I do one command as root and quit. Try `sudo whoami` to see that it says for that one command you're root. 32 | 33 | ![sudo make me a sandwich](./images/sandwich.png) 34 | 35 | xkcd comic by Randall Munroe, [link here][sandwich] 36 | 37 | It sort of feels a bit like [Simon Says][simon], right? 38 | 39 | So why can ubuntu masquerade as root? It's because ubuntu (the user) has superuser privileges, or sometimes is called sudoer. Let's try being a user that can't sudo. 40 | 41 | ```bash 42 | sudo useradd brian 43 | sudo passwd brian 44 | # make a password, I made something simple like "asdf" 45 | su brian 46 | # your new password 47 | whoami 48 | sudo su 49 | # brian is not in the sudoers file. This incident will be reported. 50 | ``` 51 | 52 | ![Incidents are reported to Santa](./images/incident.png) 53 | 54 | xkcd comic by Randall Munroe, [link here][incident] 55 | 56 | As illustarted above, don't worry about the "incidents". I used to worry that I was doing something wrong and the dean of the CS department was going to call me into his office. Turns out they didn't even know how to check those incidents. 57 | 58 | Okay, so nowe have a new user, brian, but brian can't sudo. How do we fix that? Groups! 59 | 60 | ## Groups 61 | 62 | Just like we can add and subtract permissions from a user in Linux, we can actually do it for whole cohorts of users using groups. This is useful for many reasons. Let's say you have a server that everyone connects to get documents. You could have one cohort of users that just needs to read / download the documents. In this case, we could make a `readers` group and give them read-only permission to all files. They'll never need to (or be able to) create new files. Now if a hacker gets ahold of their credentials, they can only read files and not wreck your server. And when we add a new user, we just add them to the `readers` group and that's it! If we need to later modify it that `readers` can add files to just one directory, we can easily make that happen by adding write permissions to one directory for the readers. See how this can streamline things? 63 | 64 | Some groups has special privileges, like the `sudo` group. These users can now `sudo` whenenver they need to. Let's add our user brian to the sudo group. Run `sudo usermod -aG sudo brian` (or `sudo usermod --append --groups sudo brian` if you want the long form) from the ubuntu account. usermod allows you to modify user accounts and `-aG` allows you to append new groups to the user. In this case, we made it so brian is now a sudoer. Try this now. 65 | 66 | ```bash 67 | su brian 68 | sudo whoami 69 | ``` 70 | 71 | And now you can see it respond root, which means you've successfully … sudone? 72 | 73 | ## Permissions 74 | 75 | Right now I'm logged in as brian but I'm in ubuntu's home directory. If you're not, run `su brian` then `cd /home/ubuntu`. 76 | 77 | Now, as brian, run `touch brian.txt`. You should see `touch: cannot touch 'brian.txt': Permission denied`. That's because everyone's home directory is locked down to themselves, so this is working as we anticipate. 78 | 79 | Run `ls -l` Let's discuss the `-rw-rw-r--` stuff you see in the first column. These are the permissions for each file and directory in that folder. Let's break it down one-by-one. It's not imperative you memorize this, just know enough to what you're looking at. 80 | 81 | `d rwx rwx rwx` 82 | 83 | The first `d` or `-` represents if it's a directory or a file. Anything with a hyphen here is a normal file. Anything width a `d` here is a directory. There are other possibilities besides just those two but most of what you're dealing with is one of these two. [See here][linux] if you want to see the others. 84 | 85 | The next three groups represent file permissions. The first groups is the file permissions for the user that owns that file. The next three are the file permissions for the group that owns that file. The last three is for everyone that is not that user or group. 86 | 87 | For each of the three, the `r` represents read permission, the `w` represents write permission, and the `x` represents execute permission. I think is best illustrated with a bunch of examples. 88 | 89 | `-rw-rw-r--` is a file, it has read-and-write permission for the user and the group, and read permission for everyone else, no write. The file is not executable. 90 | 91 | `drwx------` is a directory that can only be written and modified by the user. It's unreadable and unwritable by the group and the rest of the system. 92 | 93 | `-rwxr-xr-x` is a file, everyone can read it, everyone can execute it, and only the user can write to it. 94 | 95 | So what is executing in this context? It means it's an executable program. If you run `ls -l /usr/bin`, you'll see many of the programs that Linux has. You'll see that these are all executable programs. That's what the `x` is, it mean that the file is a program that can be run. 96 | 97 | We'll talk about how Linux knows where these files are in a bit, but if you run `echo $PATH` you'll see that `/usr/local/bin` is in there. 98 | 99 | Okay, so back to where we are, if you say `touch brian.txt` as brian in ubuntu's home it won't let you. But try `sudo touch brian.txt` it will work. If you do `ls -l` you'll see it wrote the file as root instead as brian. If we wanted brian to be able to write here, we'd have to change the permissions of the ubuntu home directory (you don't want to do that.) 100 | 101 | ## chown 102 | 103 | Okay, so let's modify some stuff then. Switch back to being the ubuntu user if you're still brian (you can run su ubuntu). 104 | 105 | Let's make a directory in the root. 106 | 107 | ```bash 108 | whoami # should say ubuntu 109 | cd / 110 | mkdir hello # permission denied, you don't have permission to do that here 111 | sudo mkdir hello # works, but now hello is owned by root:root 112 | ls -l # notice hello is owned by root:root 113 | touch hello/text.txt # permission denied, you don't own hello 114 | sudo chown ubuntu:ubuntu hello # it's : 115 | ls -l # notice hello is now owned by ubuntu:ubuntu 116 | touch hello/text.txt # works! 117 | ``` 118 | 119 | This is what chown does! It allows you to reassign ownership (**ch**ange **own**er). 120 | 121 | In general this is not something you need to do a ton of but it's occasionally useful. 122 | 123 | ## chmod 124 | 125 | chmod syntax is delightfully obtuse. Did you come in prepared to do some binary-to-decimal math in your head? Because here we go. 126 | 127 | So chmod allows you to directly change the permissions of the file rather just changing the owners. So instead saying "now ubuntu can write to this folder insetad of brian" we can say "any person in this ground can read from it" or "everyone on this computer can read from it". Let's do a few examples. 128 | 129 | So let's try a few 130 | 131 | ```bash 132 | whoami # should be ubuntu still 133 | cd ~ # go to home directory 134 | sudo touch secret.txt # make a file as root 135 | ls -l secret.txt # -rw-r--r-- so root can read and write but no one else can 136 | echo "very secret message" >> secret.txt # doesn't work, permission denied 137 | sudo chmod u=rw,g=rw,o=rw secret.txt # make it so anyone can read or write to the file 138 | echo "very secret message" >> secret.txt # works this time! 139 | cat secret.txt # should see very secret message 140 | ``` 141 | 142 | So that's the easy-to-remember chmod syntax. Just use u=rwx syntax (omit things you don't want the permission for.) The `u` is for user, `g` is for group, and `o` is for other or everybody else. The `r` is for read, the `w` is for write, and the `x` is for execute. 143 | 144 | Okay, so now for binary. There is a shortcut for doing this with number instead of `u=rwx,` and it involves binary. Instead of saying `chmod u=rwx,g=rwx,o=rwx file.txt` you can say `chmod 777 file.txt` and those mean the same thing. Why? Because someone was feeling very lazy. 145 | 146 | The magic formula is that you can add 4 to the number is you want to add read, add 2 for write, add 1 for executable, and set to 0 if you want zero permissions. Then do that for each and put the numbers in the order of user, group, other. So `chmod 640 secret.txt` would make it read+write for the user, read for the group, and no permission for anyone else. Why do I teach you this? Because you'll see `chmod 777 stuff.txt` out on StackOverflow and it's a bad idea. It's a hack. It makes a file accessibile to anyone and that's a bad idea. Going back to our principle of least power, we just want to grant the minimal permissions possible. 147 | 148 | One last one you'll see is the use of `+` and `-`. If you want to make a file executable, you can say `chmod +x secret.txt` and it'll add executable to each of the permissions. As you may imagine `chmod -x secret.txt` takes it away. You can use it with w and r too, just that's not super common to do. 149 | 150 | And that's it for permission! There's a lot more to learn here but this is a great start for you. 151 | 152 | [sarah]: https://frontendmasters.com/teachers/sarah-drasner/ 153 | [incident]: https://xkcd.com/838/ 154 | [sandwich]: https://xkcd.com/149/ 155 | [simon]: https://en.wikipedia.org/wiki/Simon_Says 156 | [linux]: https://www.linux.com/training-tutorials/file-types-linuxunix-explained-detail/ 157 | -------------------------------------------------------------------------------- /lessons/variables.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/variables" 3 | title: "Variables" 4 | order: "9B" 5 | section: "Shell Scripts" 6 | description: "As a developer writes more complicated scripts they need to use variables to make it more flexible. Brian goes over how to set and use variables" 7 | --- 8 | 9 | As you write more complicated scripts you need to use variables to make it more flexible. The way to do this is to use variables. Can you imagine writing code without use variables? It's possible, I suppose, but certainly not fun. And let's not do it! 10 | 11 | ## Setting a Variable 12 | 13 | This is a short section! It's very easy to set a variable. and you've already done it. Modify ~/bin/gen_files to be as follow: 14 | 15 | ```bash 16 | #! /bin/bash 17 | 18 | DESTINATION=~/temp 19 | FILE_PREFIX=file 20 | 21 | mkdir -p $DESTINATION 22 | cd $DESTINATION 23 | touch ${FILE_PREFIX}{1..10}.txt 24 | echo done 25 | ``` 26 | 27 | As you can see above, setting a variable is as easy as saying `NAME=value`. You can use quotes too, optionally. You do not have to make them uppercase though I suggest you do as that's what's normal for bash scripts. 28 | 29 | Below we're using them like we used environmental variables before (hint: those are really just variables too.) 30 | 31 | Let's talk about `touch ${FILE_PREFIX}{1..10}.txt`. Whereas we don't need the `{}` the first two times we refer to a variable, we do on this one. That's because we're inserting it in the middle of something. The `{}` let bash know where the variable names stops. The first two you can totally use them too e.g. `cd ${DESTINATION}` but it's optional. As a reminder, if you use `$()` it means a subcommand like `touch $(whoami).txt`. 32 | 33 | ## User Input 34 | 35 | So what if we want users to be able to define the file prefix? Easy! There's a program called `read` that will get user input and define a variable based on it. Try it by running `read name && echo hello $name` 36 | 37 | So let's stick that in there 38 | 39 | ```bash 40 | #! /bin/bash 41 | 42 | DESTINATION=~/temp 43 | read -p "enter a file prefix: " FILE_PREFIX 44 | 45 | mkdir -p $DESTINATION 46 | cd $DESTINATION 47 | touch ${FILE_PREFIX}{1..10}.txt 48 | echo done 49 | ``` 50 | 51 | The `-p` flag allows us to **p**rompt the user with a string, letting them know what we're expecting 52 | 53 | ## Arguments 54 | 55 | What if we want the user to be able to pass in the path to where we want to create the directory? We can do that via arguments (sometimes called parameters too.) We want the user to be able say `gen_files ~/different_directory` and use that input as \$DESTINATION. Easy! 56 | 57 | ```bash 58 | #! /bin/bash 59 | 60 | DESTINATION=$1 61 | read -p "enter a file prefix: " FILE_PREFIX 62 | 63 | mkdir -p $DESTINATION 64 | cd $DESTINATION 65 | touch ${FILE_PREFIX}{1..10}.txt 66 | echo done 67 | ``` 68 | 69 | Here we just replaced what went into `DESTINATION` with `$1`. We totally could have replaced everywhere there was DESTINATION with $1, but it was easier (and made the script clearer) by replacing the contents of DESTINATION with $1. 70 | 71 | `$0` is available here too. It'll be `gen_files`. And if you gave two arguments, the second one will be `$2` and so on and so forth. 72 | -------------------------------------------------------------------------------- /lessons/vim.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/vim" 3 | title: "vim" 4 | order: "4B" 5 | section: "Editors" 6 | description: "Brian answers the age old question: how do you exit vim? In this section Brian goes over the very basics of vim so it will never intimidate you again." 7 | --- 8 | 9 | Dare I say this is the most polarizing text editor of all time. People either will die on a hill protecting its glory or love to rag on how difficult it is to use. I think they're both right to some degree. People who learn vim very well can achieve less friction between their intent and their tool which will make you very productive. However the sort of time you have to invest into your tool to achieve that is on the order of years. If you want to spend years mastering it and customizing it to your perfection, this is the tool for you. In any case, I have elected not to; I love VSCode for its useful middleground of approachable and powerful and for its incredible ecosystem of plugins. 10 | 11 | vim has a long history but let's take a brief look at it. The genesis of the ideas that went into vim started with an editor called [ed][ed] (said ee-dee) which itself was inspired by a previous editor called [qed][qed]. ed was developed by Ken Thompson at Bell Labs in 1969. It is a line-oriented editor and I have no clue how to use it. It's actually rather well known for being pretty user unfriendly. In spite of this, it's still available on most Unix-like systems including Ubuntu and macOS. If you do start it, just know it's CTRL+D a few times to quit it. It's important to note that ed was created in a time where memory was precious, screens were tiny and sometimes just one line at a time, and modems were measured in bits, not even kilobits. It arose at a time when it fit its constraints. 12 | 13 | From ed we got [ex][ex] (short for extended). ex was still one of these line editors but it had a nicer face on it and made a bit more friendly. ex itself learned a lot from two previous iterations, en and em. From there, Bill Joy made a screen-oriented mode (as opposed to a line-oriented one) for ex that he called vi (short just for visual). Eventually this became the dominant face of ex so much that vi became the name of the program and ex became a mode inside of vi. To this day ex mode is available in vi and vim. If you run the `ex` program from Ubuntu or macOS, it just opens vim. 14 | 15 | And now we arrive to vim iteslf. Tim Thompson made a vi clone for the Atari ST called Stevie that Bram Moolenaar then ported to the Amiga. Bram called this Vi IMitation but later that was change to Vi IMproved. With vim, they made a bunch of quality-of-life improvements and made the product much easier to use to the point that people rarely use vi directly anymore and just use vim. If you run `vi` on macOS or Ubuntu it just runs vim. 16 | 17 | That's probably more history than you wanted but I always found the tale fascinating. It wonderfully demonstrates how our industry progresses. The editor I work on, Visual Studio Code, owes a lot of its core ideas to vim, nano, and all the editors before them. 18 | 19 | ## Using vim 20 | 21 | Let's start vim. Type `vim textfile.txt` to open the file you previously wrote. 22 | 23 | ![screenshot of vim with textfile.txt open](./images/vim.png) 24 | 25 | vim has multiple _modes_ you can put the editor into. By default we are in command mode. So if you start typing, nothing will appear and you may actually accidentally trigger some commands. If you want to kick the editor into insert mode, just hit `i`. You should see `-- INSERT --` at the bottom to let you know you can type now. I'm going to put `And now I'm writing this from vim.` at the bottom of the file. Once I'm done writing and want to head back to command mode, you can hit Esc. You'll see the `-- INSERT --` disappear. 26 | 27 | vim has an absolute myriad of commands and I'm not going to get into it. A good example is that here in command mode, you can use H to move the cursor left, j goes down, k goes up, and l goes right (the arrow keys work too but vim masters try to not take their fingers off the home row keys.) If I highlight a character and hit x, it'll delete that character. If I move my cursor to a line and type `:d` it'll delete the whole line. If I type `:d3` it'll delete three lines. There are so, so many and you just have to learn them. 28 | 29 | If you do desire to go in-depth on vim, you can do one of two things. One is to type `:help tutor` from the command mode and it'll start the tutor. A more fun way is [vim adventures][vim-adventures] which is a fun game to learn the keys. 30 | 31 | So, now we have our file modified the way we want to so let's save. Type `:w`. That's how you save. Now you can quit without a warning. Type `:q` and you'll quit out. If you want to do that in one motion, type `:wq` and it'll write then quit. 32 | 33 | If you try to quit with unsaved changes it won't let you. You either have to save or you can type `:q!` and it will quit without saving. 34 | 35 | Lastly, as we all find ourselves sometimes, `:q` may not work. The end-all way is `:qa!` which basically says "try to gracefully quit everything and if not, just quit anyway." 36 | 37 | The one editor I didn't talk about but you should know about is [emacs][emacs]. Feel free to glance it but I've never found myself in a situation that I've had to use emacs so we'll continue on. 38 | 39 | [ed]: https://en.wikipedia.org/wiki/Ed_(text_editor) 40 | [ex]: https://en.wikipedia.org/wiki/Ex_(text_editor) 41 | [qed]: https://en.wikipedia.org/wiki/QED_(text_editor) 42 | [vim-adventures]: https://vim-adventures.com/ 43 | [emacs]: https://www.gnu.org/software/emacs/ 44 | -------------------------------------------------------------------------------- /lessons/wget.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/wget" 3 | title: "wget" 4 | order: "7C" 5 | section: "Networking and the Internet" 6 | description: "Frequently developers will want to interact with the network. Linux provides two command lines that are very well poised to help a developer out. Brian talks about the first of the two most popular, wget." 7 | --- 8 | 9 | Frequently you will want to send requests to the Internet and/or network. The two most common tools to do that are wget and curl. Both of these are common to find in use so I'll take the time to show you both but they do relatively do the same thing. In general I'd suggest you stick to using curl; it's a more powerful tool that can do (almost) everything wget can. 10 | 11 | ## wget 12 | 13 | wget works like cp but instead of copying a local file you're copying something off the net. So you'll identify a remote file (usually a URL) that you want to fetch and save to your local file system. So let's give that a shot. 14 | 15 | We're going to go grab a [2048][2048] game off of GitHub written by the [GitHub user mydzor][mydzor]. (I forked it to my GitHub in case I ever need to update this course.) 16 | 17 | ```bash 18 | wget https://raw.githubusercontent.com/btholt/bash2048/master/bash2048.sh 19 | chmod 700 bash2048.sh 20 | . bash2048.sh 21 | ``` 22 | 23 | That wget gets the file, the chmod 700 makes the file executable, readable, and writable for the current user (and no one else) and the `. bash2048.sh` executes the game. Pretty cool, right? Very cool project. Feel free to play for a second. When you're done, hit CTRL+C to exit. It does exit the shell entirely so may need to open a new shell after via Multipass. 24 | 25 | wget can do a lot more than this, including be able to post and various other ways of shaping requests. Just say `wget --help` to see the myriad options available to you. 26 | 27 | So why learn a bit about wget? wget is a GNU project and it's available _everywhere_. Frequently you'll find tutorials that use it so I wanted you to have a bit of familiarity with it. Now let's get into curl which is the one I recommend you invest more into that wget. Know and be aware of wget but learn curl. 28 | 29 | The one case you'll want to use wget is if you want recursive downloads of site. wget has a peculiar ability that it will read the incoming document and download all the links it finds within it, crawling all the documents until it downloads all the files it founds. That can occasionally be useful and not something curl does by itself. 30 | 31 | [mydzor]: https://github.com/mydzor/bash2048 32 | -------------------------------------------------------------------------------- /lessons/what-is-linux.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/what-is-linux" 3 | title: "What is Linux" 4 | order: "2B" 5 | description: "What is Linux? Why do you need it? Brian goes into why we need Linux and where it came from" 6 | section: "Linux" 7 | --- 8 | 9 | I'm not going to give you _too_ much of a history lesson here but I think it's useful to know why something was created to understand what problems it can solve for you. 10 | 11 | # Unix 12 | 13 | Linux is considered a [Unix-like][ul] operating system which basically means that Linux derives heavy inspiration from Unix without actually conforming to be a full Unix operating system. macOS and FreeBSD would be two more examples of a Unix-like operating system. 14 | 15 | Unix was created in the 70s at Bell Labs (from which descended AT&T) and has pretty much inspired every operating system created since then. Nearly everything you're going to learn today was originated in Unix itself. A big part of Unix software is the idea of the "[Unix philosophy][up]" which is a sort of digital minimalism when it comes to coding. The idea is instead of having a few very specialized tools (or programs) we should have many small, composable tools that we can use to compose to solve larger problems. The influence of this is still felt and talked about today. Hopefully today you'll learn many of these principles. Here's what they originally wrote: 16 | 17 | - Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features". 18 | - Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input. 19 | - Design and build software, even operating systems, to be tried early, ideally within weeks. Don't hesitate to throw away the clumsy parts and rebuild them. 20 | - Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you've finished using them. 21 | 22 | I still think there's a lot of wisdom here and it's something I try to incorporate into my coding. 23 | 24 | ![Timeline of Unix-like architectures](./images/linux_timeline.png) 25 | 26 | By Guillem, Wereon, Hotmocha (copied from old version's history)Christoph S. (redrew the image with Inkscape) - Original image: Image:Unix.png, Public Domain, Link 27 | 28 | # Linux 29 | 30 | Again, Linux isn't directly Unix, just directly inspired by it, and incorporates many of its ideas and interfaces into it. It was created in 1991 by Linus Torvalds who is still an influential figure today and still runs the Linux project. He created Linux because at the time there was no single free, open-source reimplementation of the Unix operating system (the BSD kernel wasn't yet available yet) so he wrote his own kernel which became known as the Linux kernel. 31 | 32 | From here the project took off and was adopted far and wide. (As of writing) all of the top 500 super computers run on Linux, much of the mobile phone market share (thanks to Android being based on Linux), and many of the servers running your favorite websites. Suffice to say, Linux is incredibly important to the modern computing world. 33 | 34 | # Why Linux 35 | 36 | So why Linux over other operating systems? 37 | 38 | First, it's free. Anyone can use Linux to do anything without paying anyone a dime. This is useful for college students who don't have any money but it's also critical for large businesses running thousands or tens-of-thousands of servers. It can save them millions of dollars to not have to pay for an operating system. 39 | 40 | It's very well maintained. Because Linux is such a popular operating system, it has a lot of eyes on it. Engineers from all over the world and all over the industry are constantly contributing fixes and new features to Linux, both on their own free time and during the course of their jobs. 41 | 42 | It runs just about anywhere. Linux not only runs on x86 (the Intel / AMD processor architecture your computer is likely using) but it runs on Internet-of-Things devices, phones, fridges, cars, etc. If it has a processor in it, chances are you can get Linux running on it already. 43 | 44 | Most of the the things you need already exist for it. Linux already has many of the tools one would need to run servers, devices, media, etc. all on it already, meaning you wouldn't need to create it. Linux has a rich ecosystem of programs available that are also likely free. 45 | 46 | The knowledgebase for Linux is enormous. Having a problem? Chances are someone else already had the same problem and you can find the solution on StackOverflow or someone's blog. Because the knowledgebase is so large, it's really easy to hire someone with deep knowledge of Linux and for you it's profitable to learn Linux because so many jobs demand the skillset. 47 | 48 | # What Makes Linux, Linux 49 | 50 | At its core, Linux is the kernel. Anything based on this Linux kernel is a considered a Linux distribution, or distro for short. 51 | 52 | ![Linux Kernel Map](./images/linux_kernel_map.png) 53 | 54 | By Conan at English Wikipedia, CC BY 3.0, Link 55 | 56 | I'm not going to go over what's in the kernel because frankly it's _way_ outside of my understanding. I did not do well in my OS's class. But suffice to say it's the core of what's need to start and run a system and nothing else. It manages the booting, memory, processes, drivers, and other lowest-level concerns of the operating system. Beyond that, the various different distros use those kernel features to build their distros on top of. 57 | 58 | A lot of these distros will share components even amongst themselves. For example, a lot of them use KDE or Gnome for their graphical desktops, and people have strong feelings about which is better (I don't care, I don't use desktop Linux!) 59 | 60 | # Distros 61 | 62 | There are so, so, so many distros of Linux. They all do different things well and some of them are very specialized in what sorts of things they can accomplish. I'm going to only introduce you primarily to one through the course of this class, [Ubuntu][ubuntu], but that's not say there aren't many good reasons to choose other ones. 63 | 64 | Why are we choosing Ubuntu? It's a very good choice for many different use cases. In my opinion, it's the best general purpose distro for many use cases. It's a _downstream_ distro of [Debian][debian] where downstream means that Ubuntu builds upon the base of Debian. Ubuntu is a very polished (when I say polished I mean it has a nice interface) distro of Linux which I think it is the easiest to use. It's backed a company called Canonical who puts a lot of love into the distro and they're definitely one of my favorite companies. 65 | 66 | Ubuntu is a great choice for running Linux on as your main OS (I don't), for servers in the cloud, for IoT, or for any other of myriad things. It's a really great, flexible distribution. 67 | 68 | I'll toss a few of the other, more popular distros for you to take a look at too. I haven't used all of them but they're popular enough that they merit a look from you. 69 | 70 | - [Debian][debian] 71 | - [Mint][mint] 72 | - [Red Hat][rhel] 73 | - [Alpine][alpine] 74 | - [Kali][kali] 75 | - [CentOS][centos] 76 | 77 | [ul]: https://en.wikipedia.org/wiki/Unix-like 78 | [up]: https://en.wikipedia.org/wiki/Unix_philosophy 79 | [debian]: https://www.debian.org/ 80 | [ubuntu]: https://ubuntu.com/ 81 | [rhel]: https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux 82 | [alpine]: https://www.alpinelinux.org/ 83 | [kali]: https://www.kali.org/ 84 | [centos]: https://www.centos.org/ 85 | [mint]: https://linuxmint.com/ 86 | -------------------------------------------------------------------------------- /lessons/what-is-package-management.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/what-is-package-management" 3 | title: "What is Package Management" 4 | order: "8A" 5 | section: "Package Management" 6 | description: "One of the best part of Linux is its infinite ocean of useful packages. Brian talks about the Ubuntu ecosystem and the ability to get packages from apt install." 7 | --- 8 | 9 | Ubuntu by itself is a very useful system but we begin to see its infinite possibilites when we dive into the packages that are available to it. Ubuntu comes with its own lovely package manager tools and I'm going to show you how to use some of them to get more tools so you can do more cool stuff. 10 | 11 | ## Each Linux Distro Has Its Own 12 | 13 | We'll be going over specifically what Ubuntu has for package management but just be aware that each Linux distro has its own package management tools. 14 | 15 | - Debian has dpkg. Because Ubuntu is based on Debian it also has dpkg installed and available to use. 16 | - APT (advanced packaging tool) is based on dpkg and available to all in the Debian family of distros 17 | - Red Hat had RPM, Red Hat Package Manager 18 | - Similar to how APT is on top of dpkg, YUM is on top of RPM to make it easier to use. DNF is the next generation of YUM 19 | - Arch has Pacman 20 | - Alpine has APK 21 | 22 | Even macOS has one with Homebrew and Windows with its new winget system. Again, we'll be focusing on APT and Snap today. 23 | 24 | ## dpkg 25 | 26 | Today we're not going to be touch dpkg at all. But it is there and you can use it. It's from Debian, the upstream for Ubuntu, and it's generally a lower level tool for more fine grained control at the cost of being a lot more difficult to use. I never use it. 27 | -------------------------------------------------------------------------------- /lessons/what-you-will-learn.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/what-will-you-learn" 3 | title: "What you will learn" 4 | order: "2A" 5 | description: "It is always good to go in knowing what you're about to learn. Brian goes over why this course is useful to you and what problems Linux is going to solve for you." 6 | section: "Linux" 7 | --- 8 | 9 | Let's chat a moment about what you're going to learn with this course and set some context. The objective of this course is teach you two principle concepts: what is Linux and why you'd use it, and how to use a command line. This two concepts I found were big barriers for developers getting started in their careers and I wanted to help demystify that. Throughout my career I've worked with developers who purposefully avoid the command line and I think that's a shame, you can do a lot of things quickly with just a bit of know-how. 10 | 11 | So today we'll cover the following: 12 | 13 | - What is Linux 14 | - What problems Linux solves for you 15 | - How Linux is generally laid out 16 | - What the command line is 17 | - Basic navigation in the command line 18 | - Common tasks with the command line 19 | - Some basic customizations 20 | 21 | I hope you'll come out the other side of this excited about what the command line and Linux can do for you! 22 | -------------------------------------------------------------------------------- /lessons/wildcards-and-replacements.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/lol" 3 | title: "Wildcards and Replacements" 4 | order: "5B" 5 | section: "Files, Pipes, and Permissions" 6 | description: "Using a few tricks you can cleverly select multiple files at a time with bash. Brian in this section will go over wilcards, expansions, and replacements" 7 | --- 8 | 9 | A brief aside here for how to select multiple files. 10 | 11 | ## Wilcards 12 | 13 | Let's you wanted to remove all the .txt files in your directory. You could say `rm file1.txt file2.txt file3.txt ` but that's time consuming. You know they all end with .txt, wouldn't it be nice if you could say "remove anything that ends in .txt"? You can! That's what the wildcard `*` is for with paths. Instead of the command above, you can do `rm *.txt` and it'll remove everything matches that pattern. If you want to try this, use the `-i` flag so it'll prompt if you want to delete the files or not so you don't accidentally things you don't mean to. 14 | 15 | Okay, so say you wanted to match file1.txt and file2.txt but not file.txt. `file*.txt` will match all three of those. For that you can use `?`. So try `file?.txt`. 16 | 17 | Try this 18 | 19 | ```bash 20 | touch file1.txt file2.txt file.txt 21 | ls file*.txt 22 | ls file?.txt 23 | ``` 24 | 25 | Notice the first ls call does output `file.txt` and the second one doesn't. 26 | 27 | A curious fact above how this (and everyhing below with expansions) works is that it's bash that does the translation of `*` and `?` and _not_ the programs. So when you say `ls file*.txt`, what `ls` actually ends up getting inputted is `ls file1.txt file2.txt file.txt`. That's important because `ls` doesn't have to support anything, which means this works anywhere in bash. 28 | 29 | So, more on `?` vs `*`. `?` represents **exactly one character**. So `file?.txt` won't match `file10.txt` either. So you could match `file1.txt` as well by doing `ls f?le1.txt` since that `?` represent any one character there. 30 | 31 | Finally you can use `[]` to limit your characters too. Let's say you wanted 1-5. So you could say `ls file[1-5].txt`. Or you can say anything that matches not these characters by saying `ls file[^1-5].txt` 32 | 33 | ## Expansions 34 | 35 | Let's say you wanted to create three files using touch all at once. You could do: 36 | 37 | ```bash 38 | touch file4.txt 39 | touch file5.txt 40 | touch file6.txt 41 | ``` 42 | 43 | It's a bit annoying but it'll work. But try this instead 44 | 45 | ```bash 46 | touch file{4,5,6}.txt 47 | touch {Aisha,Lanie,Joumana,Krista}-profile.txt 48 | ``` 49 | 50 | Even better, try this: 51 | 52 | ```bash 53 | touch file{0..10}.txt 54 | ``` 55 | 56 | Pretty cool right? Okay, let's get a couple more advance ones in there. We'll use echo from now one to not fill up our folder with garbage files but know this works anywhere in bash. 57 | 58 | ```bash 59 | echo {a..z} # prints a to z 60 | echo {z..a} # reverse order 61 | echo {0..100..2} # prints every other (aka even) number from 0 to 100 62 | echo {100..0..5} # prints every 5th number in reverse order from 100 to 0 63 | echo {a..z}{1..5} # prints out a1 a2 a3 a4 a5 b1 b2 b3 64 | ``` 65 | 66 | Are these useful all the time? No, but when they are they can save you a bunch of time! 67 | -------------------------------------------------------------------------------- /lessons/writing-your-own-scripts.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/writing-your-own-scripts" 3 | title: "Writing Your Own Scripts" 4 | order: "9A" 5 | section: "Shell Scripts" 6 | description: "Often times you want do more than just one command at a time; you want to run many of them. Bash allows you to put many commands into one file to create a program of programs which is called a shell script." 7 | --- 8 | 9 | Often times you want do more than just one command at a time; you want to run many of them. Bash allows you to put many commands into one file to create a program of programs which is called a shell script. 10 | 11 | How that work? Well, secretly, you have been learning a programming language this entire time. Bash is actually a programming language and you have been learning it this whole time. We have been just been running it one line at a time via a REPL. You can actually do this with Python or Node.js too. Try just running `python3` or `node`. It will drop you in a similar style REPL (FYI, to quit either node or python3, use CTRL+D.) 12 | 13 | ## My First Bashscript 14 | 15 | Let's make our first bash script. Let's make make a directory called temp, generate ten files, and exit. Basically we want to make a bashscript that does this: 16 | 17 | ```bash 18 | mkdir -p ~/temp # -p mean don't error if it exists in this case, it does other things too 19 | cd ~/temp 20 | touch file{1..10}.txt 21 | echo done 22 | ``` 23 | 24 | So let's do that. You can use either vi or nano, both work. So run `vi gen_files.sh` or `nano gen_files.sh`. From there, put the above code in it and save. 25 | 26 | Also, you can cd freely within a script: it only changes the working directory for that shell script, not for the user. The user in their interactive shell won't 27 | 28 | Now, to run it, do `. gen_files.sh` or `source gen_files.sh` or `bash gen_files.sh`. Any of those work the same way. 29 | 30 | ## Hashbang 31 | 32 | Notice we didn't have to make gen_files.sh an executable file. That's because we're not actually executing it directly: we're executing bash or source (source and . are the same thing) and those are executing our program. But what if wanted to actually make it a new command that we didn't have to feed into source or bash? What if we could basically make it indistiguishable from a normal command like cp or curl? You can! Let's see how. 33 | 34 | Open `gen_files.sh` and put this **as the very first line**. I bold that because it must be the first line. 35 | 36 | ```bash 37 | #! /bin/bash 38 | ``` 39 | 40 | This line (called a shebang, hashbang, or many other things; often ! is called a bang in computing) lets bash know how to execute this file. It must be on the first line and it must start with `#!`. It's then always followed by the absolute path (meaning it starts with `/` and gives you the full path; you cannot give it a relative e.g. `./bash`). This works with Python, for example. If you want a script to executed by python3, you can find the path of any program by saying `which `. So if we want to know where python3 is, we can say `which python3` and get the path from that. 41 | 42 | Okay, so now we have a hashbang in place. However the file now needs the executable permission. Let's do that. Run `chmod 700 gen_files.sh`. Now you can run `./gen_files.sh` without anything running as the executable. We need the `./` because gen_files.sh isn't on our PATH yet (I'll explain that very shortly.) 43 | 44 | ## PATH 45 | 46 | Okay, so right now you have to give a path to be able to run gen_files.sh. What if we want to be able to run `gen_files` from anywhere on our computer? We can do that! 47 | 48 | Your user a variable set called `PATH`. Your PATH is a series of locations of where programs live. If I say `python3`, it goes through each of those locations and checks for anything called `python3`. If there are two, it uses the first one it finds (the path furthest left in the path.) 49 | 50 | You can see your PATH if you run `echo $PATH`. You should see something like `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin` (it may not be exactly this.) 51 | 52 | In general I don't mess any of those directories. All of those are system wide bin directories (if you had more than one user they'd share them.) 53 | So a good idea is to have your own `~/bin` directory. So let's do that. 54 | 55 | ```bash 56 | cd ~ 57 | mkdir bin 58 | mv gen_files.sh bin/gen_files 59 | PATH=~/bin:$PATH 60 | echo $PATH 61 | gen_files 62 | ``` 63 | 64 | Hooray! Now it works! We added ~/bin to our path so now bash will try to execute anything we put in there. We added ~/bin to the front of our path and that's a good idea. If, for example, wanted a different rm program than the default one, we don't want to mess with the system one, just ours. We would want ours to "shadow" the system one and to not mess with everyone else's rm. 65 | 66 | When we set the PATH, we used PATH to define itself. Keep in mind that bash will replace that \$PATH _before_ it runs our command so by the time we try to set the variable it's just a string. That's why that works. 67 | 68 | Lastly, we only set the PATH for just this session. Once we close our terminal, it'll go away. However we can add this line to our .bashrc and it'll always get set! Run `vi ~/.bashrc` (or nano) and add this line somewhere: 69 | 70 | ```bash 71 | PATH=~/bin:$PATH 72 | ``` 73 | 74 | Multipass already had a lot of stuff in there for me so don't get overwhelmed. You can put that line just about anywhere. Whenever you make a change to .bashrc you have to rerun it or it won't take effect on your current session. Run `. ~/.bashrc` and you'll be set. 75 | 76 | ## Comments 77 | 78 | If you want to add comments, you just add `#` and then from there you can put anything after it. You've probably notice me doing it before this. 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "complete-intro-to-linux-and-the-cli", 3 | "description": "the course website for the Complete Intro to Linux and the Command Line", 4 | "version": "1.0.0", 5 | "author": "Brian Holt ", 6 | "dependencies": { 7 | "bootstrap": "^5.1.3", 8 | "code-mirror-themes": "^1.0.0", 9 | "front-matter": "^4.0.2", 10 | "gatsby": "^4.6.2", 11 | "gatsby-cli": "^4.6.1", 12 | "gatsby-link": "^4.6.0", 13 | "gatsby-plugin-layout": "^3.6.0", 14 | "gatsby-plugin-react-helmet": "^5.6.0", 15 | "gatsby-plugin-sharp": "4.6.0", 16 | "gatsby-remark-autolink-headers": "^5.6.0", 17 | "gatsby-remark-copy-linked-files": "^5.6.0", 18 | "gatsby-remark-images": "^6.6.0", 19 | "gatsby-remark-prismjs": "^6.6.0", 20 | "gatsby-source-filesystem": "^4.6.0", 21 | "gatsby-transformer-remark": "^5.6.0", 22 | "is-url-superb": "^5.0.0", 23 | "parse-markdown-links": "^1.0.4", 24 | "prismjs": "^1.26.0", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "react-helmet": "^6.1.0" 28 | }, 29 | "keywords": [ 30 | "gatsby", 31 | "gatsby-starter", 32 | "course", 33 | "education" 34 | ], 35 | "license": "(CC-BY-NC-4.0 OR Apache-2.0)", 36 | "main": "n/a", 37 | "scripts": { 38 | "build": "gatsby build --prefix-paths", 39 | "csv": "node csv.js", 40 | "dev": "gatsby develop", 41 | "format": "prettier --write \"src/**/*.{js,jsx,md,css}\"", 42 | "lint": "eslint \"src/**/*.{js,jsx}\"", 43 | "deploy": "gatsby build --prefix-paths && gh-pages -d public -b gh-pages" 44 | }, 45 | "devDependencies": { 46 | "@babel/polyfill": "^7.12.1", 47 | "babel-eslint": "^10.1.0", 48 | "core-js": "^3.21.0", 49 | "eslint": "^8.8.0", 50 | "eslint-config-prettier": "^8.3.0", 51 | "eslint-plugin-import": "^2.25.4", 52 | "eslint-plugin-jsx-a11y": "^6.5.1", 53 | "eslint-plugin-react": "^7.28.0", 54 | "prettier": "^2.5.1", 55 | "gh-pages": "^3.2.3" 56 | } 57 | } -------------------------------------------------------------------------------- /src/components/TOCCard.css: -------------------------------------------------------------------------------- 1 | .main-card { 2 | border: 1px solid #ccc; 3 | border-radius: 8px; 4 | width: 100%; 5 | margin: 0; 6 | overflow: hidden; 7 | background-color: white; 8 | } 9 | 10 | .lesson-title { 11 | font-size: 20px; 12 | padding: 15px 30px; 13 | text-align: center; 14 | } 15 | 16 | .lesson-content { 17 | padding: 0 15px 15px 15px; 18 | line-height: 1.5; 19 | } 20 | 21 | .sections-name { 22 | list-style: none; 23 | } 24 | 25 | .lesson-section-title { 26 | margin-top: 25px; 27 | } 28 | 29 | .toc-image { 30 | max-width: 100%; 31 | max-height: 52px; 32 | } 33 | -------------------------------------------------------------------------------- /src/components/TOCCard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import * as helpers from "../util/helpers"; 4 | import "./TOCCard.css"; 5 | 6 | const sortFn = helpers.sorter; 7 | 8 | const LessonCard = ({ content }) => { 9 | const sections = content 10 | .map(lesson => lesson.node.frontmatter) 11 | .sort(sortFn) 12 | .reduce((acc, lesson) => { 13 | if (!acc.length) { 14 | acc.push([lesson]); 15 | return acc; 16 | } 17 | 18 | const lastSection = acc[acc.length - 1][0].section.split(",")[0]; 19 | if (lastSection === lesson.section.split(",")[0]) { 20 | acc[acc.length - 1].push(lesson); 21 | } else { 22 | acc.push([lesson]); 23 | } 24 | 25 | return acc; 26 | }, []); 27 | 28 | return ( 29 |
30 |

31 | table of content 36 |

37 |
38 |
    39 | {sections.map(section => ( 40 |
  1. 41 |

    {section[0].section}

    42 |
      43 | {section.map(lesson => ( 44 |
    1. 45 | {lesson.title} 46 |
    2. 47 | ))} 48 |
    49 |
  2. 50 | ))} 51 |
52 |
53 |
54 | ); 55 | }; 56 | 57 | export default LessonCard; 58 | -------------------------------------------------------------------------------- /src/layouts/index.css: -------------------------------------------------------------------------------- 1 | .gradient { 2 | background: #92aad7; 3 | background: linear-gradient(to bottom, #a5d8f4 0%, #92aad7 100%); 4 | } 5 | 6 | .navbar { 7 | border-bottom: 1px solid #ccc; 8 | position: sticky; 9 | width: 100%; 10 | top: 0; 11 | z-index: 10; 12 | display: flex; 13 | justify-content: space-between; 14 | align-items: center; 15 | flex-wrap: nowrap; 16 | padding: 10px; 17 | } 18 | 19 | .navbar-brand { 20 | font-size: 20px; 21 | margin: inherit; 22 | padding: inherit; 23 | font-weight: bold; 24 | max-width: 60%; 25 | } 26 | 27 | .navbar-brand-image { 28 | max-width: 100%; 29 | max-height: 52px; 30 | } 31 | 32 | .navbar h2 { 33 | font-size: 14px; 34 | margin: inherit; 35 | padding: inherit; 36 | text-transform: uppercase; 37 | color: white; 38 | max-width: 40%; 39 | } 40 | 41 | @media only screen and (max-width: 600px) { 42 | .navbar { 43 | flex-wrap: wrap; 44 | flex-direction: column; 45 | } 46 | .navbar-brand { 47 | width: 100%; 48 | max-width: 100%; 49 | } 50 | 51 | .navbar h2 { 52 | width: 100%; 53 | max-width: 100%; 54 | text-align: center; 55 | } 56 | } 57 | 58 | .button { 59 | border-radius: 10px; 60 | padding: 0; 61 | background: #0066cc; 62 | color: white; 63 | display: flex; 64 | justify-content: center; 65 | align-items: center; 66 | text-decoration: none; 67 | } 68 | 69 | .button .icon { 70 | padding-left: 5px; 71 | display: inline-block; 72 | } 73 | 74 | .button a { 75 | padding: 3px 8px; 76 | color: white; 77 | text-decoration: none; 78 | } 79 | 80 | @media (max-width: 1450px) { 81 | .mobile-hidden { 82 | display: none; 83 | } 84 | .lesson-container { 85 | padding-top: 65px; 86 | } 87 | } 88 | 89 | .button:hover { 90 | background: #0d6efd; 91 | } 92 | 93 | .jumbotron.gradient { 94 | color: white; 95 | text-transform: uppercase; 96 | font-weight: bold; 97 | } 98 | 99 | .navbar-brand.navbar-brand { 100 | text-transform: uppercase; 101 | color: white; 102 | font-weight: bold; 103 | } 104 | 105 | .navbar-brand.navbar-brand:hover { 106 | color: #777; 107 | } 108 | 109 | .navbar-brand.navbar-brand:focus { 110 | color: white; 111 | } 112 | 113 | .lesson { 114 | margin: 15px; 115 | padding: 15px; 116 | background-color: #fff; 117 | border-radius: 8px; 118 | overflow: scroll; 119 | } 120 | 121 | .lesson p { 122 | clear: both; 123 | } 124 | 125 | .lesson-links { 126 | font-size: 18px; 127 | padding: 15px 0; 128 | } 129 | 130 | .next { 131 | float: right; 132 | } 133 | 134 | .prev { 135 | float: left; 136 | } 137 | 138 | .lesson-title { 139 | color: white; 140 | text-transform: uppercase; 141 | font-weight: bold; 142 | } 143 | 144 | .doggos { 145 | width: 100%; 146 | border: 1px solid #666; 147 | border-radius: 5px; 148 | } 149 | -------------------------------------------------------------------------------- /src/layouts/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import Helmet from "react-helmet"; 4 | import { graphql, StaticQuery } from "gatsby"; 5 | 6 | import "bootstrap/dist/css/bootstrap.css"; 7 | import "prismjs/themes/prism-solarizedlight.css"; 8 | import "code-mirror-themes/themes/monokai.css"; 9 | import "./index.css"; 10 | 11 | import jpg from "../../static/WORDMARK-Small.png"; 12 | 13 | const TemplateWrapper = props => { 14 | return ( 15 | { 17 | const frontmatter = 18 | props.data && props.data.markdownRemark 19 | ? props.data.markdownRemark.frontmatter 20 | : null; 21 | 22 | return ( 23 |
24 | 70 |
71 | 72 | the complete intro to linux and the cli 77 | 78 | {!frontmatter ? null : ( 79 |

{`${frontmatter.section} – ${frontmatter.title}`}

80 | )} 81 |

82 | 83 | Complete Intro to Linux & Command Line Videos 84 |  ▶️  85 | 86 |

87 |
88 |
{props.children}
89 |
90 | ); 91 | }} 92 | query={graphql` 93 | query HomePage($path: String!) { 94 | markdownRemark(frontmatter: { path: { eq: $path } }) { 95 | html 96 | frontmatter { 97 | path 98 | title 99 | order 100 | section 101 | description 102 | } 103 | } 104 | site { 105 | pathPrefix 106 | siteMetadata { 107 | title 108 | subtitle 109 | description 110 | keywords 111 | } 112 | } 113 | } 114 | `} 115 | /> 116 | ); 117 | }; 118 | 119 | export default TemplateWrapper; 120 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const NotFoundPage = () => ( 4 |
5 |

NOT FOUND

6 |

You just hit a route that doesn't exist... the sadness.

7 |
8 | ); 9 | 10 | export default NotFoundPage; 11 | -------------------------------------------------------------------------------- /src/pages/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #dcecf4; 3 | background-image: url(https://btholt.github.io/complete-intro-to-linux-and-the-cli/WALLPAPER.jpg); 4 | } 5 | 6 | .index { 7 | width: 97%; 8 | max-width: 750px; 9 | margin: 0 auto; 10 | margin-top: 20px; 11 | } 12 | 13 | .index .jumbotron { 14 | padding: 0; 15 | background-color: rgba(0, 0, 0, 0); 16 | } 17 | 18 | .jumbotron-hero { 19 | width: 100%; 20 | } 21 | 22 | .example-table { 23 | border-collapse: separate; 24 | } 25 | 26 | .example-table td { 27 | border: 1px solid black; 28 | width: 20px; 29 | height: 20px; 30 | } 31 | 32 | .example-table .current { 33 | background-color: #fcc; 34 | } 35 | 36 | .example-table .n { 37 | border-top-color: transparent; 38 | } 39 | 40 | .example-table .s { 41 | border-bottom-color: transparent; 42 | } 43 | 44 | .example-table .e { 45 | border-right-color: transparent; 46 | } 47 | 48 | .example-table .w { 49 | border-left-color: transparent; 50 | } 51 | 52 | .lesson-content table { 53 | } 54 | 55 | .lesson-content td { 56 | border: 1px solid black; 57 | padding: 8px; 58 | } 59 | 60 | .lesson-content td input { 61 | min-width: 300px; 62 | } 63 | 64 | .lesson-flex { 65 | display: flex; 66 | flex-direction: column; 67 | justify-content: center; 68 | align-items: center; 69 | } 70 | 71 | .random-tweet { 72 | width: 100%; 73 | margin-top: 100px; 74 | } 75 | 76 | .fem-link { 77 | text-align: center; 78 | } 79 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StaticQuery, graphql } from "gatsby"; 3 | import Card from "../components/TOCCard"; 4 | 5 | import "./index.css"; 6 | 7 | const IndexPage = () => ( 8 | ( 36 |
37 |
38 | intro to linux and the cli 43 |
44 | 45 | 49 |
50 | )} 51 | /> 52 | ); 53 | 54 | export default IndexPage; 55 | -------------------------------------------------------------------------------- /src/templates/lessonTemplate.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import { graphql } from "gatsby"; 4 | import * as helpers from "../util/helpers"; 5 | 6 | const sortFn = helpers.sorter; 7 | 8 | export default function Template(props) { 9 | let { markdownRemark, allMarkdownRemark } = props.data; // data.markdownRemark holds our post data 10 | 11 | const sections = allMarkdownRemark.edges 12 | .map(lesson => lesson.node.frontmatter) 13 | .sort(sortFn); 14 | 15 | const { frontmatter, html } = markdownRemark; 16 | 17 | const index = sections.findIndex(el => el.path === frontmatter.path); 18 | 19 | const prevLink = 20 | index > 0 ? ( 21 | 22 | {"← " + sections[index - 1].title} 23 | 24 | ) : null; 25 | const nextLink = 26 | index < sections.length - 1 ? ( 27 | 28 | {sections[index + 1].title + " →"} 29 | 30 | ) : null; 31 | return ( 32 |
33 |
34 |

{frontmatter.title}

35 |

{frontmatter.date}

36 |
40 |
41 | {prevLink} 42 | {nextLink} 43 |
44 |
45 |
46 | ); 47 | } 48 | 49 | export const pageQuery = graphql` 50 | query LessonByPath($path: String!) { 51 | markdownRemark(frontmatter: { path: { eq: $path } }) { 52 | html 53 | frontmatter { 54 | path 55 | title 56 | order 57 | section 58 | description 59 | } 60 | } 61 | allMarkdownRemark(limit: 1000) { 62 | edges { 63 | node { 64 | frontmatter { 65 | order 66 | path 67 | title 68 | } 69 | } 70 | } 71 | } 72 | } 73 | `; 74 | -------------------------------------------------------------------------------- /src/util/helpers.js: -------------------------------------------------------------------------------- 1 | function splitSections(str) { 2 | const validSectionTest = /^\d+[A-Z]+$/; 3 | const numbersRegex = /^\d+/; 4 | const lettersRegex = /[A-Z]+$/; 5 | if (!validSectionTest.test(str)) { 6 | throw new Error( 7 | `${str} does not match the section format. It must be , like 16A or 5F (case sensitive)` 8 | ); 9 | } 10 | 11 | return [numbersRegex.exec(str)[0], lettersRegex.exec(str)[0]]; 12 | } 13 | 14 | const getCharScore = str => 15 | str 16 | .split("") 17 | .map((char, index) => char.charCodeAt(0) * 10 ** index) 18 | .reduce((acc, score) => acc + score); 19 | 20 | function sorter(a, b) { 21 | let aOrder, bOrder; 22 | 23 | if (a.attributes && a.attributes.order) { 24 | aOrder = a.attributes.order; 25 | bOrder = b.attributes.order; 26 | } else { 27 | aOrder = a.order; 28 | bOrder = b.order; 29 | } 30 | 31 | const [aSec, aSub] = splitSections(aOrder); 32 | const [bSec, bSub] = splitSections(bOrder); 33 | 34 | // sections first 35 | if (aSec !== bSec) { 36 | return aSec - bSec; 37 | } 38 | 39 | // subsections next 40 | return getCharScore(aSub) - getCharScore(bSub); 41 | } 42 | 43 | module.exports.splitSections = splitSections; 44 | module.exports.sorter = sorter; 45 | -------------------------------------------------------------------------------- /static/HEADER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/static/HEADER.png -------------------------------------------------------------------------------- /static/TOC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/static/TOC.png -------------------------------------------------------------------------------- /static/WALLPAPER.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/static/WALLPAPER.jpg -------------------------------------------------------------------------------- /static/WORDMARK-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/static/WORDMARK-Small.png -------------------------------------------------------------------------------- /static/posterframe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btholt/complete-intro-to-linux-and-the-cli/38b0b295a2e28a9437981316d8b89ab7a587c565/static/posterframe.jpg --------------------------------------------------------------------------------