<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ command line - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ command line - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 18 May 2026 22:34:37 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/command-line/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Learn Command Line Interface (CLI) Development with Dart: From Zero to a Fully Published Developer Tool ]]>
                </title>
                <description>
                    <![CDATA[ Most developers spend a significant portion of their day in the terminal. They run flutter build, push with git, manage packages with dart pub, and orchestrate pipelines from the command line. Every o ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-command-line-interface-cli-development-with-dart-from-zero-to-a-fully-published-developer-tool/</link>
                <guid isPermaLink="false">69fe3149f239332df4fdfd46</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cli ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mobile Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwaseyi Fatunmole ]]>
                </dc:creator>
                <pubDate>Fri, 08 May 2026 18:54:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/a4c564c2-f5f3-4824-b4e7-d103b5fc488e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most developers spend a significant portion of their day in the terminal. They run <code>flutter build</code>, push with <code>git</code>, manage packages with <code>dart pub</code>, and orchestrate pipelines from the command line. Every one of those tools is a CLI, or command line interface: a program that lives in the terminal and responds to text commands.</p>
<p>Yet most developers have never built one.</p>
<p>That's a missed opportunity. CLI tools are one of the most practical things a developer can ship. They automate repetitive workflows, standardise processes across teams, and, when published, become tangible artifacts that the developer community can discover, install, and use.</p>
<p>In this handbook, you'll go from zero to building a fully distributed Dart CLI tool. We'll start with the fundamentals – how CLIs work, how Dart receives and processes terminal input, and the core syntax you need to know. Then we'll build three progressively complex CLIs, starting with the basics and finishing with a real-world API request runner. Finally, we will cover every distribution path available, from <code>pub.dev</code> to compiled binaries, Homebrew taps, Docker, and local team activation.</p>
<p>By the end of the guide, you'll understand both how to build a CLI tool in Dart as well as how to ship it so other developers can actually use it.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-what-is-a-cli-and-why-should-you-build-one">What is a CLI and Why Should You Build One?</a></p>
</li>
<li><p><a href="#heading-cli-syntax-anatomy">CLI Syntax Anatomy</a></p>
</li>
<li><p><a href="#heading-how-dart-receives-terminal-input">How Dart Receives Terminal Input</a></p>
</li>
<li><p><a href="#heading-core-cli-concepts-in-dart">Core CLI Concepts in Dart</a></p>
<ul>
<li><p><a href="#heading-stdout-stderr-and-stdin">stdout, stderr, and stdin</a></p>
</li>
<li><p><a href="#heading-exit-codes">Exit Codes</a></p>
</li>
<li><p><a href="#heading-environment-variables">Environment Variables</a></p>
</li>
<li><p><a href="#heading-file-and-directory-operations">File and Directory Operations</a></p>
</li>
<li><p><a href="#heading-running-external-processes">Running External Processes</a></p>
</li>
<li><p><a href="#heading-platform-detection">Platform Detection</a></p>
</li>
<li><p><a href="#heading-async-in-cli">Async in CLI</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-setting-up-your-dart-cli-project">Setting Up Your Dart CLI Project</a></p>
</li>
<li><p><a href="#heading-cli-1-hello-cli-the-fundamentals">CLI 1 — Hello CLI: The Fundamentals</a></p>
</li>
<li><p><a href="#heading-cli-2-darttodo-a-terminal-task-manager">CLI 2 — dart_todo: A Terminal Task Manager</a></p>
<ul>
<li><p><a href="#heading-introducing-the-args-package">Introducing the args Package</a></p>
</li>
<li><p><a href="#heading-building-darttodo">Building dart_todo</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-cli-3-darthttp-a-lightweight-api-request-runner">CLI 3 — dart_http: A Lightweight API Request Runner</a></p>
<ul>
<li><a href="#heading-building-darthttp">Building dart_http</a></li>
</ul>
</li>
<li><p><a href="#heading-adding-color-and-polish-to-your-cli">Adding Color and Polish to Your CLI</a></p>
</li>
<li><p><a href="#heading-testing-your-cli-tool">Testing Your CLI Tool</a></p>
</li>
<li><p><a href="#heading-deploying-and-distributing-your-cli">Deploying and Distributing Your CLI</a></p>
<ul>
<li><p><a href="#heading-mode-1-pubdev-public-package-distribution">Mode 1: pub.dev — Public Package Distribution</a></p>
</li>
<li><p><a href="#heading-mode-2-local-path-activation">Mode 2: Local Path Activation</a></p>
</li>
<li><p><a href="#heading-mode-3-compiled-binary-via-github-releases">Mode 3: Compiled Binary via GitHub Releases</a></p>
</li>
<li><p><a href="#heading-mode-4-homebrew-tap">Mode 4: Homebrew Tap</a></p>
</li>
<li><p><a href="#heading-mode-5-docker">Mode 5: Docker</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-choosing-the-right-distribution-mode">Choosing the Right Distribution Mode</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before starting, you should have:</p>
<ul>
<li><p>Dart SDK installed (<code>dart --version</code> should work in your terminal)</p>
</li>
<li><p>Basic familiarity with Dart syntax</p>
</li>
<li><p>Comfort with the terminal and running commands</p>
</li>
<li><p>A pub.dev account (for the publishing section)</p>
</li>
<li><p>A GitHub account (for the binary distribution section)</p>
</li>
</ul>
<h2 id="heading-what-is-a-cli-and-why-should-you-build-one">What is a CLI and Why Should You Build One?</h2>
<p>A CLI (or <strong>Command Line Interface</strong>) is a program you interact with entirely through text commands in a terminal, rather than through buttons and screens in a graphical interface.</p>
<p>Many of the tools you likely already rely on as a developer are CLI tools:</p>
<pre><code class="language-yaml">flutter build apk
git commit -m "fix: auth flow"
dart pub get
npm install
</code></pre>
<p>Flutter, Git, Dart, npm – all CLIs. You are already a CLI user every single day. This article is about becoming a CLI builder.</p>
<p>There are three strong reasons to build CLI tools as a developer:</p>
<ol>
<li><p><strong>Automating repetitive work:</strong> Anything you type more than twice a week is a candidate for automation. Generating boilerplate folder structures, running sequences of commands, scaffolding files, checking environments before a build a CLI turns a seven-step manual process into a single command.</p>
</li>
<li><p><strong>Standardising team workflows:</strong> Instead of a README that says "run these commands in this order," you ship one command that does all of it – consistently, every time, with no room for human error or a missed step.</p>
</li>
<li><p><strong>Building and publishing tooling.</strong> A published Dart CLI package is a tangible artifact. It shows up on pub.dev, gets installed and used by other developers, and communicates real engineering depth in a way that a portfolio or resume cannot.</p>
</li>
</ol>
<h2 id="heading-cli-syntax-anatomy">CLI Syntax Anatomy</h2>
<p>Before writing a single line of code, it helps to understand the structure of a CLI command. Every command follows a consistent pattern:</p>
<pre><code class="language-bash">tool [subcommand] [arguments] [options/flags]
</code></pre>
<p>Breaking down a real example:</p>
<pre><code class="language-bash">flutter build apk --release --obfuscate
│       │     │   │
tool    sub   arg  flags
</code></pre>
<ul>
<li><p><strong>Tool</strong> — the program itself (<code>flutter</code>, <code>dart</code>, <code>git</code>)</p>
</li>
<li><p><strong>Subcommand</strong> — the action being performed (<code>build</code>, <code>run</code>, <code>pub</code>)</p>
</li>
<li><p><strong>Arguments</strong> — what the action operates on (<code>apk</code>, <code>main.dart</code>, a filename)</p>
</li>
<li><p><strong>Flags and Options</strong> — modifiers that change behaviour</p>
</li>
</ul>
<p>There are two types of options:</p>
<pre><code class="language-plaintext">--release              # Boolean flag — either present or absent

--output=build/app     # Key-value option — name and a value
-v                     # Short flag — single hyphen, single character
</code></pre>
<p>This is the anatomy your CLIs will follow. Understanding it before writing any code means you will design your commands intentionally rather than stumbling into structure by accident.</p>
<h2 id="heading-how-dart-receives-terminal-input">How Dart Receives Terminal Input</h2>
<p>In Dart, everything the user types after your tool name is passed into your program through the <code>main</code> function:</p>
<pre><code class="language-dart">void main(List&lt;String&gt; args) {
  print(args);
}
</code></pre>
<p>Run it:</p>
<pre><code class="language-bash">dart run bin/mytool.dart hello world --name=Seyi
# [hello, world, --name=Seyi]
</code></pre>
<p>That <code>List&lt;String&gt; args</code> is just a list of strings. Each word or flag the user typed becomes an element in that list. Everything else you build on top of a CLI subcommands, flags, validation — is ultimately just processing this list.</p>
<h2 id="heading-core-cli-concepts-in-dart">Core CLI Concepts in Dart</h2>
<p>Before building anything, there's a set of foundational concepts that every CLI developer needs to understand. These are the building blocks that everything else sits on top of.</p>
<h3 id="heading-stdout-stderr-and-stdin">stdout, stderr, and stdin</h3>
<p>Most developers use <code>print()</code> for all output when they start building CLIs. That works for learning but it's incorrect in production.</p>
<p>There are two separate output streams in a terminal program:</p>
<ul>
<li><p><code>stdout</code> — regular output, meant for the user</p>
</li>
<li><p><code>stderr</code> — error output, meant for diagnostic messages and failures</p>
</li>
</ul>
<pre><code class="language-dart">import 'dart:io';

void main(List&lt;String&gt; args) {
  if (args.isEmpty) {
    stderr.writeln('Error: no arguments provided');
    exit(1);
  }

  stdout.writeln('Processing: ${args[0]}');
}
</code></pre>
<p>Keeping these separate matters because users can redirect stdout to a file without errors polluting it:</p>
<pre><code class="language-bash">dart run bin/tool.dart &gt; output.txt
# Errors still appear in the terminal
# Normal output goes cleanly to the file
</code></pre>
<p>Tools like <code>git</code>, <code>flutter</code>, and <code>curl</code> all do this correctly. Your CLI should too.</p>
<p><code>stdin</code> is the third stream — reading input from the user interactively at runtime:</p>
<pre><code class="language-dart">import 'dart:io';

void main() {
  stdout.write('Enter your name: ');
  final name = stdin.readLineSync();

  if (name == null || name.trim().isEmpty) {
    stderr.writeln('Error: no name provided');
    exit(1);
  }

  stdout.writeln('Hello, $name!');
}
</code></pre>
<p><code>stdout.write</code> (without <code>ln</code>) keeps the cursor on the same line so the user types right after the prompt. <code>stdin.readLineSync()</code> blocks until the user presses Enter and returns the typed string, or <code>null</code> if the stream closes unexpectedly. Always handle the null case.</p>
<h3 id="heading-exit-codes">Exit Codes</h3>
<p>Every program returns an exit code when it finishes. This is how the shell – and any script or CI system calling your tool – knows whether it succeeded or failed.</p>
<pre><code class="language-dart">import 'dart:io';

void main(List&lt;String&gt; args) {
  if (args.isEmpty) {
    stderr.writeln('Error: please provide an argument');
    exit(1); // failure
  }

  stdout.writeln('Done');
  exit(0); // success — also the default if you don't call exit()
}
</code></pre>
<p>The conventions are:</p>
<ul>
<li><p><code>0</code> — success</p>
</li>
<li><p><code>1</code> — general failure</p>
</li>
<li><p><code>2</code> — incorrect usage (wrong arguments, missing flags)</p>
</li>
</ul>
<p>Exit codes are critical when your CLI is called inside shell scripts or GitHub Actions workflows. A non-zero exit code stops a pipeline immediately. That's exactly the behaviour you want from a quality gate or a validation step.</p>
<h3 id="heading-environment-variables">Environment Variables</h3>
<p>Your CLI can read environment variables set in the user's shell:</p>
<pre><code class="language-dart">import 'dart:io';

void main() {
  final token = Platform.environment['API_TOKEN'];

  if (token == null) {
    stderr.writeln('Error: API_TOKEN environment variable is not set');
    exit(1);
  }

  stdout.writeln('Token found — proceeding...');
}
</code></pre>
<p>Set it in the terminal and run:</p>
<pre><code class="language-bash">export API_TOKEN=mytoken123
dart run bin/tool.dart
# Token found — proceeding...
</code></pre>
<p>This pattern is essential for CLI tools that interact with APIs, cloud services, or CI environments where credentials should never be hardcoded.</p>
<h3 id="heading-file-and-directory-operations">File and Directory Operations</h3>
<p>Many CLI tools read from or write to the file system. Dart's <code>dart:io</code> library covers everything you need:</p>
<pre><code class="language-dart">import 'dart:io';

void main(List&lt;String&gt; args) {
  if (args.isEmpty) {
    stderr.writeln('Usage: tool &lt;filename&gt;');
    exit(2);
  }

  final file = File(args[0]);

  if (!file.existsSync()) {
    stderr.writeln('Error: "${args[0]}" not found');
    exit(1);
  }

  final contents = file.readAsStringSync();
  stdout.writeln(contents);

  final output = File('output.txt');
  output.writeAsStringSync('Processed:\n$contents');
  stdout.writeln('Written to output.txt');
}
</code></pre>
<p>Working with directories:</p>
<pre><code class="language-dart">import 'dart:io';

void main() {
  // Where the command was run from
  final cwd = Directory.current.path;
  stdout.writeln('Working directory: $cwd');

  // Create a directory relative to current location
  final dir = Directory('$cwd/generated');

  if (!dir.existsSync()) {
    dir.createSync(recursive: true);
    stdout.writeln('Created: ${dir.path}');
  } else {
    stdout.writeln('Already exists: ${dir.path}');
  }
}
</code></pre>
<p>The <code>recursive: true</code> flag on <code>createSync</code> means it creates all intermediate directories — equivalent to <code>mkdir -p</code> in bash.</p>
<h3 id="heading-running-external-processes">Running External Processes</h3>
<p>One of the most powerful things a CLI can do is call other programs. Your Dart CLI can run <code>git</code>, <code>flutter</code>, <code>dart</code>, or any shell command programmatically:</p>
<pre><code class="language-dart">import 'dart:io';

void main() async {
  // Run a command and wait for it to finish
  final result = await Process.run('dart', ['pub', 'get']);

  stdout.write(result.stdout);

  if (result.exitCode != 0) {
    stderr.write(result.stderr);
    exit(result.exitCode);
  }

  stdout.writeln('Dependencies installed successfully');
}
</code></pre>
<p>For long-running commands where you want output to stream live as it happens:</p>
<pre><code class="language-dart">import 'dart:io';

void main() async {
  final process = await Process.start('flutter', ['build', 'apk']);

  // Pipe output directly to the terminal in real time
  process.stdout.pipe(stdout);
  process.stderr.pipe(stderr);

  final exitCode = await process.exitCode;
  exit(exitCode);
}
</code></pre>
<p><code>Process.run</code> — waits for completion, returns all output at once. Use for short commands.</p>
<p><code>Process.start</code> — streams output live as it arrives. Use for long-running commands where the user needs to see progress.</p>
<h3 id="heading-platform-detection">Platform Detection</h3>
<p>Sometimes your CLI needs to behave differently depending on the operating system it is running on:</p>
<pre><code class="language-dart">import 'dart:io';

void main() {
  if (Platform.isWindows) {
    stdout.writeln('Running on Windows');
  } else if (Platform.isMacOS) {
    stdout.writeln('Running on macOS');
  } else if (Platform.isLinux) {
    stdout.writeln('Running on Linux');
  }

  // Useful for path handling across operating systems
  stdout.writeln(Platform.pathSeparator); // \ on Windows, / elsewhere
  stdout.writeln(Platform.operatingSystem); // 'macos', 'linux', 'windows'
}
</code></pre>
<p>This matters when your CLI creates files, resolves paths, or calls shell commands that differ between operating systems.</p>
<h3 id="heading-async-in-cli">Async in CLI</h3>
<p>Dart CLIs support <code>async/await</code> natively. Any <code>main</code> function can be made async:</p>
<pre><code class="language-dart">import 'dart:io';

void main() async {
  stdout.writeln('Starting...');

  await Future.delayed(const Duration(seconds: 1)); // simulating async work

  stdout.writeln('Done');
}
</code></pre>
<p>Any operation involving file I/O, HTTP requests, or spawning processes will be asynchronous. Get comfortable with async <code>main</code> functions early — you'll use them constantly.</p>
<h2 id="heading-setting-up-your-dart-cli-project">Setting Up Your Dart CLI Project</h2>
<p>Create a new Dart console project:</p>
<pre><code class="language-bash">dart create -t console my_cli_tool
cd my_cli_tool
</code></pre>
<p>This generates a clean structure:</p>
<pre><code class="language-plaintext">my_cli_tool/
  bin/
    my_cli_tool.dart    ← entry point
  lib/                  ← shared library code
  test/                 ← tests
  pubspec.yaml
  README.md
</code></pre>
<p>The <code>bin/</code> directory is where your executable entry point lives. The <code>lib/</code> directory is where you put everything else — commands, utilities, models — that <code>bin/</code> imports and uses.</p>
<p>Open <code>pubspec.yaml</code>. You'll need to add an <code>executables</code> block before publishing:</p>
<pre><code class="language-yaml">name: my_cli_tool
description: A sample CLI tool built with Dart
version: 1.0.0

environment:
  sdk: '&gt;=3.0.0 &lt;4.0.0'

executables:
  my_cli_tool: my_cli_tool  # executable name: bin file name

dependencies:
  args: ^2.4.2

dev_dependencies:
  lints: ^3.0.0
  test: ^1.24.0
</code></pre>
<p>The <code>executables</code> block is what makes <code>dart pub global activate my_cli_tool</code> work. It tells Dart which script in <code>bin/</code> to expose as a runnable command after installation.</p>
<h2 id="heading-cli-1-hello-cli-the-fundamentals">CLI 1 — Hello CLI: The Fundamentals</h2>
<p>This first CLI uses pure Dart — no packages. The goal is to get comfortable with args, subcommands, input validation, and exit codes before introducing any external dependencies.</p>
<p>Replace the contents of <code>bin/my_cli_tool.dart</code>:</p>
<pre><code class="language-dart">import 'dart:io';

void main(List&lt;String&gt; args) {
  if (args.isEmpty) {
    printHelp();
    exit(0);
  }

  final command = args[0];

  switch (command) {
    case 'greet':
      handleGreet(args.sublist(1));
    case 'time':
      handleTime();
    case 'echo':
      handleEcho(args.sublist(1));
    case 'help':
      printHelp();
    default:
      stderr.writeln('Unknown command: "$command"');
      stderr.writeln('Run "mytool help" to see available commands.');
      exit(1);
  }
}

void handleGreet(List&lt;String&gt; args) {
  if (args.isEmpty) {
    stderr.writeln('Usage: mytool greet &lt;name&gt;');
    exit(2);
  }

  final name = args[0];
  stdout.writeln('Hello, $name! Welcome to your first Dart CLI.');
}

void handleTime() {
  final now = DateTime.now();
  stdout.writeln(
    'Current time: ${now.hour.toString().padLeft(2, '0')}:'
    '${now.minute.toString().padLeft(2, '0')}:'
    '${now.second.toString().padLeft(2, '0')}',
  );
}

void handleEcho(List&lt;String&gt; args) {
  if (args.isEmpty) {
    stderr.writeln('Usage: mytool echo &lt;message&gt;');
    exit(2);
  }

  stdout.writeln(args.join(' '));
}

void printHelp() {
  stdout.writeln('''
mytool — a simple Dart CLI

Usage:
  mytool &lt;command&gt; [arguments]

Commands:
  greet &lt;name&gt;      Greet someone by name
  time              Show the current time
  echo &lt;message&gt;    Echo a message back to the terminal
  help              Show this help message

Examples:
  mytool greet Seyi
  mytool echo "Hello from the terminal"
  mytool time
  ''');
}
</code></pre>
<p>Run it:</p>
<pre><code class="language-bash">dart run bin/my_cli_tool.dart help

dart run bin/my_cli_tool.dart greet Seyi
# Hello, Seyi! Welcome to your first Dart CLI.

dart run bin/my_cli_tool.dart time
# Current time: 14:32:10

dart run bin/my_cli_tool.dart echo "Dart CLIs are powerful"
# Dart CLIs are powerful

dart run bin/my_cli_tool.dart unknown
# Unknown command: "unknown"
# Run "mytool help" to see available commands.
</code></pre>
<p>Three things this CLI demonstrates that are worth internalising:</p>
<ol>
<li><p><strong>Subcommands are just a switch on</strong> <code>args[0]</code><strong>.</strong> The pattern is simple and scalable — add a new <code>case</code> to add a new command.</p>
</li>
<li><p><code>args.sublist(1)</code> <strong>passes remaining args to the handler.</strong> When <code>greet</code> receives <code>['greet', 'Seyi']</code>, it calls <code>handleGreet(['Seyi'])</code> — clean and isolated.</p>
</li>
<li><p><strong>Every error path has a message and a non-zero exit code.</strong> The user always knows what went wrong and what to do next.</p>
</li>
</ol>
<h2 id="heading-cli-2-darttodo-a-terminal-task-manager">CLI 2 — dart_todo: A Terminal Task Manager</h2>
<p>This CLI introduces the <code>args</code> package, JSON file persistence, and structured terminal output. It's meaningfully more complex than CLI 1 and reflects real patterns you will use in production tools.</p>
<h3 id="heading-introducing-the-args-package">Introducing the args Package</h3>
<p>Manually parsing <code>List&lt;String&gt; args</code> works for simple cases, but breaks down quickly when you add flags like <code>--priority=high</code>, boolean options like <code>--done</code>, or commands with multiple optional arguments.</p>
<p>The <code>args</code> package handles all of that cleanly.</p>
<p>Add it to your <code>pubspec.yaml</code>:</p>
<pre><code class="language-yaml">dependencies:
  args: ^2.4.2
</code></pre>
<p>Run:</p>
<pre><code class="language-bash">dart pub get
</code></pre>
<p>The core concept in <code>args</code> is the <code>ArgParser</code>. You define what your CLI accepts, and <code>args</code> handles parsing, validation, and generating help text automatically:</p>
<pre><code class="language-dart">import 'package:args/args.dart';

void main(List&lt;String&gt; arguments) {
  final parser = ArgParser()
    ..addCommand('add')
    ..addCommand('list')
    ..addFlag('help', abbr: 'h', negatable: false);

  final results = parser.parse(arguments);

  if (results['help'] as bool) {
    print(parser.usage);
    return;
  }
}
</code></pre>
<p>For more complex CLIs with subcommands that each have their own flags, use <code>ArgParser</code> per command:</p>
<pre><code class="language-dart">final parser = ArgParser();

final addCommand = ArgParser()
  ..addOption('priority', abbr: 'p', defaultsTo: 'normal');

parser.addCommand('add', addCommand);
</code></pre>
<h3 id="heading-building-darttodo">Building dart_todo</h3>
<p>Create a fresh project:</p>
<pre><code class="language-bash">dart create -t console dart_todo
cd dart_todo
</code></pre>
<p>Update <code>pubspec.yaml</code>:</p>
<pre><code class="language-yaml">name: dart_todo
description: A terminal task manager built with Dart
version: 1.0.0

environment:
  sdk: '&gt;=3.0.0 &lt;4.0.0'

executables:
  dart_todo: dart_todo

dependencies:
  args: ^2.4.2

dev_dependencies:
  lints: ^3.0.0
  test: ^1.24.0
</code></pre>
<p>Run <code>dart pub get</code>.</p>
<p>Create the folder structure:</p>
<pre><code class="language-plaintext">dart_todo/
  bin/
    dart_todo.dart
  lib/
    models/
      task.dart
    storage/
      task_storage.dart
    commands/
      add_command.dart
      list_command.dart
      complete_command.dart
      delete_command.dart
      clear_command.dart
  pubspec.yaml
</code></pre>
<h4 id="heading-step-1-the-task-model-libmodelstaskdart">Step 1 — The Task Model (<code>lib/models/task.dart</code>)</h4>
<pre><code class="language-dart">class Task {
  final int id;
  final String title;
  final String priority;
  final bool isComplete;
  final DateTime createdAt;

  Task({
    required this.id,
    required this.title,
    required this.priority,
    this.isComplete = false,
    required this.createdAt,
  });

  Task copyWith({bool? isComplete}) {
    return Task(
      id: id,
      title: title,
      priority: priority,
      isComplete: isComplete ?? this.isComplete,
      createdAt: createdAt,
    );
  }

  Map&lt;String, dynamic&gt; toJson() =&gt; {
        'id': id,
        'title': title,
        'priority': priority,
        'isComplete': isComplete,
        'createdAt': createdAt.toIso8601String(),
      };

  factory Task.fromJson(Map&lt;String, dynamic&gt; json) =&gt; Task(
        id: json['id'] as int,
        title: json['title'] as String,
        priority: json['priority'] as String,
        isComplete: json['isComplete'] as bool,
        createdAt: DateTime.parse(json['createdAt'] as String),
      );
}
</code></pre>
<h4 id="heading-step-2-storage-libstoragetaskstoragedart">Step 2 — Storage (<code>lib/storage/task_storage.dart</code>)</h4>
<p>This class handles reading and writing tasks to a local JSON file so they persist between CLI runs:</p>
<pre><code class="language-dart">import 'dart:convert';
import 'dart:io';

import '../models/task.dart';

class TaskStorage {
  static final _file = File(
    '${Platform.environment['HOME'] ?? Directory.current.path}/.dart_todo.json',
  );

  static List&lt;Task&gt; loadAll() {
    if (!_file.existsSync()) return [];

    try {
      final content = _file.readAsStringSync();
      final List&lt;dynamic&gt; json = jsonDecode(content) as List&lt;dynamic&gt;;
      return json
          .map((e) =&gt; Task.fromJson(e as Map&lt;String, dynamic&gt;))
          .toList();
    } catch (_) {
      return [];
    }
  }

  static void saveAll(List&lt;Task&gt; tasks) {
    final json = jsonEncode(tasks.map((t) =&gt; t.toJson()).toList());
    _file.writeAsStringSync(json);
  }
}
</code></pre>
<p>Tasks are stored in a hidden JSON file in the user's home directory — a common pattern for CLI tools that need lightweight local persistence.</p>
<h4 id="heading-step-3-commands">Step 3 — Commands</h4>
<p><code>lib/commands/add_command.dart</code>:</p>
<pre><code class="language-dart">import 'dart:io';

import '../models/task.dart';
import '../storage/task_storage.dart';

void runAdd(List&lt;String&gt; args, String priority) {
  if (args.isEmpty) {
    stderr.writeln('Usage: dart_todo add &lt;title&gt; [--priority=high|normal|low]');
    exit(2);
  }

  final title = args.join(' ');
  final tasks = TaskStorage.loadAll();

  final newTask = Task(
    id: tasks.isEmpty ? 1 : tasks.last.id + 1,
    title: title,
    priority: priority,
    createdAt: DateTime.now(),
  );

  tasks.add(newTask);
  TaskStorage.saveAll(tasks);

  stdout.writeln('Added task #\({newTask.id}: "\)title" [$priority]');
}
</code></pre>
<p><code>lib/commands/list_command.dart</code>:</p>
<pre><code class="language-cpp">import 'dart:io';

import '../storage/task_storage.dart';

void runList() {
  final tasks = TaskStorage.loadAll();

  if (tasks.isEmpty) {
    stdout.writeln('No tasks yet. Add one with: dart_todo add &lt;title&gt;');
    return;
  }

  stdout.writeln('');
  stdout.writeln('  ID   Status      Priority   Title');
  stdout.writeln('  ───  ──────────  ─────────  ────────────────────────');

  for (final task in tasks) {
    final status = task.isComplete ? 'done  ' : 'pending';
    final id = task.id.toString().padRight(4);
    final priority = task.priority.padRight(9);
    stdout.writeln('  \(id \)status  \(priority  \){task.title}');
  }

  stdout.writeln('');
}
</code></pre>
<p><code>lib/commands/complete_command.dart</code>:</p>
<pre><code class="language-dart">import 'dart:io';

import '../storage/task_storage.dart';

void runComplete(List&lt;String&gt; args) {
  if (args.isEmpty) {
    stderr.writeln('Usage: dart_todo complete &lt;id&gt;');
    exit(2);
  }

  final id = int.tryParse(args[0]);
  if (id == null) {
    stderr.writeln('Error: "${args[0]}" is not a valid task ID');
    exit(1);
  }

  final tasks = TaskStorage.loadAll();
  final index = tasks.indexWhere((t) =&gt; t.id == id);

  if (index == -1) {
    stderr.writeln('Error: No task found with ID $id');
    exit(1);
  }

  if (tasks[index].isComplete) {
    stdout.writeln('Task #$id is already complete.');
    return;
  }

  tasks[index] = tasks[index].copyWith(isComplete: true);
  TaskStorage.saveAll(tasks);

  stdout.writeln('Task #\(id marked as complete: "\){tasks[index].title}"');
}
</code></pre>
<p><code>lib/commands/delete_command.dart</code>:</p>
<pre><code class="language-dart">import 'dart:io';

import '../storage/task_storage.dart';

void runDelete(List&lt;String&gt; args) {
  if (args.isEmpty) {
    stderr.writeln('Usage: dart_todo delete &lt;id&gt;');
    exit(2);
  }

  final id = int.tryParse(args[0]);
  if (id == null) {
    stderr.writeln('Error: "${args[0]}" is not a valid task ID');
    exit(1);
  }

  final tasks = TaskStorage.loadAll();
  final index = tasks.indexWhere((t) =&gt; t.id == id);

  if (index == -1) {
    stderr.writeln('Error: No task found with ID $id');
    exit(1);
  }

  final title = tasks[index].title;
  tasks.removeAt(index);
  TaskStorage.saveAll(tasks);

  stdout.writeln('Deleted task #\(id: "\)title"');
}
</code></pre>
<p><code>lib/commands/clear_command.dart</code>:</p>
<pre><code class="language-dart">import 'dart:io';

import '../storage/task_storage.dart';

void runClear() {
  stdout.write('Are you sure you want to delete all tasks? (y/N): ');
  final input = stdin.readLineSync()?.trim().toLowerCase();

  if (input != 'y') {
    stdout.writeln('Cancelled.');
    return;
  }

  TaskStorage.saveAll([]);
  stdout.writeln('All tasks cleared.');
}
</code></pre>
<h4 id="heading-step-4-entry-point-bindarttododart">Step 4 — Entry Point (<code>bin/dart_todo.dart</code>)</h4>
<pre><code class="language-dart">import 'dart:io';

import 'package:args/args.dart';

import '../lib/commands/add_command.dart';
import '../lib/commands/clear_command.dart';
import '../lib/commands/complete_command.dart';
import '../lib/commands/delete_command.dart';
import '../lib/commands/list_command.dart';

void main(List&lt;String&gt; arguments) {
  final parser = ArgParser();

  // Add subcommand parsers
  final addParser = ArgParser()
    ..addOption(
      'priority',
      abbr: 'p',
      defaultsTo: 'normal',
      allowed: ['high', 'normal', 'low'],
      help: 'Task priority level',
    );

  parser
    ..addCommand('add', addParser)
    ..addCommand('list')
    ..addCommand('complete')
    ..addCommand('delete')
    ..addCommand('clear')
    ..addFlag('help', abbr: 'h', negatable: false, help: 'Show help');

  ArgResults results;

  try {
    results = parser.parse(arguments);
  } catch (e) {
    stderr.writeln('Error: $e');
    stderr.writeln(parser.usage);
    exit(2);
  }

  if (results['help'] as bool || results.command == null) {
    printHelp(parser);
    exit(0);
  }

  final command = results.command!;

  switch (command.name) {
    case 'add':
      runAdd(command.rest, command['priority'] as String);
    case 'list':
      runList();
    case 'complete':
      runComplete(command.rest);
    case 'delete':
      runDelete(command.rest);
    case 'clear':
      runClear();
    default:
      stderr.writeln('Unknown command: "${command.name}"');
      exit(1);
  }
}

void printHelp(ArgParser parser) {
  stdout.writeln('''
dart_todo — a terminal task manager

Usage:
  dart_todo &lt;command&gt; [arguments]

Commands:
  add &lt;title&gt;        Add a new task
    -p, --priority   Priority: high, normal, low (default: normal)
  list               List all tasks
  complete &lt;id&gt;      Mark a task as complete
  delete &lt;id&gt;        Delete a task
  clear              Delete all tasks

Examples:
  dart_todo add "Write the CLI article" --priority=high
  dart_todo list
  dart_todo complete 1
  dart_todo delete 2
  dart_todo clear
  ''');
}
</code></pre>
<p>Run it:</p>
<pre><code class="language-bash">dart run bin/dart_todo.dart add "Write the CLI article" --priority=high
# Added task #1: "Write the CLI article" [high]

dart run bin/dart_todo.dart add "Review PR comments"
# Added task #2: "Review PR comments" [normal]

dart run bin/dart_todo.dart list
#   ID   Status      Priority   Title
#   ───  ──────────  ─────────  ────────────────────────
#   1    ⬜ pending  high       Write the CLI article
#   2    ⬜ pending  normal     Review PR comments

dart run bin/dart_todo.dart complete 1
# Task #1 marked as complete: "Write the CLI article"

dart run bin/dart_todo.dart delete 2
# Deleted task #2: "Review PR comments"
</code></pre>
<p><code>dart_todo</code> demonstrates the patterns that form the backbone of almost every real CLI tool — argument parsing with <code>args</code>, JSON persistence, interactive prompts, structured output, and clean error handling across every command.</p>
<h2 id="heading-cli-3-darthttp-a-lightweight-api-request-runner">CLI 3 — dart_http: A Lightweight API Request Runner</h2>
<p>This is the most complex CLI in this article – and the most immediately useful. <code>dart_http</code> lets developers make HTTP requests directly from the terminal, with pretty-printed JSON responses, response metadata, header support, and the ability to save responses to a file.</p>
<pre><code class="language-bash">dart_http get https://jsonplaceholder.typicode.com/users/1
dart_http post https://jsonplaceholder.typicode.com/posts --body='{"title":"Hello"}'
dart_http get https://jsonplaceholder.typicode.com/users --save=users.json
dart_http get https://api.example.com/me --header="Authorization: Bearer mytoken"
</code></pre>
<h3 id="heading-building-darthttp">Building dart_http</h3>
<p>Create the project:</p>
<pre><code class="language-bash">dart create -t console dart_http
cd dart_http
</code></pre>
<p>Update <code>pubspec.yaml</code>:</p>
<pre><code class="language-yaml">name: dart_http
description: A lightweight API request runner for the terminal
version: 1.0.0

environment:
  sdk: '&gt;=3.0.0 &lt;4.0.0'

executables:
  dart_http: dart_http

dependencies:
  args: ^2.4.2
  http: ^1.2.1

dev_dependencies:
  lints: ^3.0.0
  test: ^1.24.0
</code></pre>
<p>Run <code>dart pub get</code>.</p>
<p>Project structure:</p>
<pre><code class="language-plaintext">dart_http/
  bin/
    dart_http.dart
  lib/
    runner/
      request_runner.dart
    printer/
      response_printer.dart
    utils/
      headers_parser.dart
  pubspec.yaml
</code></pre>
<h4 id="heading-step-1-headers-parser-libutilsheadersparserdart">Step 1 — Headers Parser (<code>lib/utils/headers_parser.dart</code>)</h4>
<pre><code class="language-dart">Map&lt;String, String&gt; parseHeaders(List&lt;String&gt; rawHeaders) {
  final headers = &lt;String, String&gt;{};

  for (final header in rawHeaders) {
    final index = header.indexOf(':');
    if (index == -1) continue;

    final key = header.substring(0, index).trim();
    final value = header.substring(index + 1).trim();
    headers[key] = value;
  }

  return headers;
}
</code></pre>
<h4 id="heading-step-2-response-printer-libprinterresponseprinterdart">Step 2 — Response Printer (<code>lib/printer/response_printer.dart</code>)</h4>
<pre><code class="language-dart">import 'dart:convert';
import 'dart:io';

void printResponse({
  required int statusCode,
  required String body,
  required int durationMs,
  required int bodyBytes,
}) {
  final statusLabel = _statusLabel(statusCode);
  final size = _formatSize(bodyBytes);

  stdout.writeln('');
  stdout.writeln('\(statusLabel | \){durationMs}ms | $size');
  stdout.writeln('─' * 50);

  try {
    final decoded = jsonDecode(body);
    const encoder = JsonEncoder.withIndent('  ');
    stdout.writeln(encoder.convert(decoded));
  } catch (_) {
    // Not JSON — print as plain text
    stdout.writeln(body);
  }

  stdout.writeln('');
}

String _statusLabel(int code) {
  if (code &gt;= 200 &amp;&amp; code &lt; 300) return '✅ $code';
  if (code &gt;= 300 &amp;&amp; code &lt; 400) return '↪️  $code';
  if (code &gt;= 400 &amp;&amp; code &lt; 500) return '❌ $code';
  return '$code';
}

String _formatSize(int bytes) {
  if (bytes &lt; 1024) return '${bytes}b';
  if (bytes &lt; 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}kb';
  return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}mb';
}
</code></pre>
<h4 id="heading-step-3-request-runner-librunnerrequestrunnerdart">Step 3 — Request Runner (<code>lib/runner/request_runner.dart</code>)</h4>
<pre><code class="language-dart">import 'dart:io';

import 'package:http/http.dart' as http;

import '../printer/response_printer.dart';

Future&lt;void&gt; runRequest({
  required String method,
  required String url,
  required Map&lt;String, String&gt; headers,
  String? body,
  String? saveToFile,
}) async {
  final uri = Uri.tryParse(url);

  if (uri == null) {
    stderr.writeln('Error: "$url" is not a valid URL');
    exit(1);
  }

  stdout.writeln('→ \({method.toUpperCase()} \)url');

  http.Response response;
  final stopwatch = Stopwatch()..start();

  try {
    switch (method.toLowerCase()) {
      case 'get':
        response = await http.get(uri, headers: headers);
      case 'post':
        response = await http.post(uri, headers: headers, body: body);
      case 'put':
        response = await http.put(uri, headers: headers, body: body);
      case 'patch':
        response = await http.patch(uri, headers: headers, body: body);
      case 'delete':
        response = await http.delete(uri, headers: headers);
      default:
        stderr.writeln('Error: unsupported method "$method"');
        exit(2);
    }
  } catch (e) {
    stderr.writeln('Error: request failed — $e');
    exit(1);
  }

  stopwatch.stop();

  printResponse(
    statusCode: response.statusCode,
    body: response.body,
    durationMs: stopwatch.elapsedMilliseconds,
    bodyBytes: response.bodyBytes.length,
  );

  if (saveToFile != null) {
    final file = File(saveToFile);
    file.writeAsStringSync(response.body);
    stdout.writeln('Response saved to $saveToFile');
  }
}
</code></pre>
<h4 id="heading-step-4-entry-point-bindarthttpdart">Step 4 — Entry Point (<code>bin/dart_http.dart</code>)</h4>
<pre><code class="language-dart">import 'dart:io';

import 'package:args/args.dart';

import '../lib/runner/request_runner.dart';
import '../lib/utils/headers_parser.dart';

void main(List&lt;String&gt; arguments) async {
  final parser = ArgParser();

  for (final method in ['get', 'post', 'put', 'patch', 'delete']) {
    final commandParser = ArgParser()
      ..addMultiOption('header', abbr: 'H', help: 'Request header (repeatable)')
      ..addOption('body', abbr: 'b', help: 'Request body (for POST/PUT/PATCH)')
      ..addOption('save', abbr: 's', help: 'Save response body to a file');

    parser.addCommand(method, commandParser);
  }

  parser.addFlag('help', abbr: 'h', negatable: false, help: 'Show help');

  ArgResults results;

  try {
    results = parser.parse(arguments);
  } catch (e) {
    stderr.writeln('Error: $e');
    printHelp();
    exit(2);
  }

  if (results['help'] as bool || results.command == null) {
    printHelp();
    exit(0);
  }

  final command = results.command!;
  final method = command.name!;
  final rest = command.rest;

  if (rest.isEmpty) {
    stderr.writeln('Error: please provide a URL');
    stderr.writeln('Usage: dart_http $method &lt;url&gt;');
    exit(2);
  }

  final url = rest[0];
  final rawHeaders = command['header'] as List&lt;String&gt;;
  final body = command['body'] as String?;
  final saveToFile = command['save'] as String?;

  final headers = parseHeaders(rawHeaders);

  // Default Content-Type for requests with a body
  if (body != null &amp;&amp; !headers.containsKey('Content-Type')) {
    headers['Content-Type'] = 'application/json';
  }

  await runRequest(
    method: method,
    url: url,
    headers: headers,
    body: body,
    saveToFile: saveToFile,
  );
}

void printHelp() {
  stdout.writeln('''
dart_http — a lightweight API request runner

Usage:
  dart_http &lt;method&gt; &lt;url&gt; [options]

Methods:
  get       Send a GET request
  post      Send a POST request
  put       Send a PUT request
  patch     Send a PATCH request
  delete    Send a DELETE request

Options:
  -H, --header    Add a request header (repeatable)
  -b, --body      Request body (JSON string)
  -s, --save      Save response body to a file
  -h, --help      Show this help message

Examples:
  dart_http get https://jsonplaceholder.typicode.com/users
  dart_http get https://api.example.com/me --header="Authorization: Bearer token"
  dart_http post https://api.example.com/posts --body=\'{"title":"Hello"}\'
  dart_http get https://api.example.com/users --save=users.json
  ''');
}
</code></pre>
<p>Run it:</p>
<pre><code class="language-bash">dart run bin/dart_http.dart get https://jsonplaceholder.typicode.com/users/1

# → GET https://jsonplaceholder.typicode.com/users/1
# 200 | 87ms | 510b
# ──────────────────────────────────────────────────
# {
#   "id": 1,
#   "name": "Leanne Graham",
#   "username": "Bret",
#   "email": "Sincere@april.biz"
# }

dart run bin/dart_http.dart get https://jsonplaceholder.typicode.com/users --save=users.json
# → GET https://jsonplaceholder.typicode.com/users
# 200 | 143ms | 5.3kb
# ──────────────────────────────────────────────────
# [ ... ]
# Response saved to users.json

dart run bin/dart_http.dart post https://jsonplaceholder.typicode.com/posts \
  --body='{"title":"Hello from dart_http","userId":1}'
# → POST https://jsonplaceholder.typicode.com/posts
# 201 | 312ms | 72b
</code></pre>
<h2 id="heading-adding-color-and-polish-to-your-cli">Adding Color and Polish to Your CLI</h2>
<p>The CLIs above are functional, but terminal output can be made significantly more readable with color. The <code>ansi_styles</code> package provides ANSI escape code support for coloring text in the terminal.</p>
<p>Add it to <code>pubspec.yaml</code>:</p>
<pre><code class="language-yaml">dependencies:
  ansi_styles: ^0.3.0
</code></pre>
<p>Using it:</p>
<pre><code class="language-dart">import 'package:ansi_styles/ansi_styles.dart';

stdout.writeln(AnsiStyles.green('✅ Success'));
stdout.writeln(AnsiStyles.red('❌ Error: something went wrong'));
stdout.writeln(AnsiStyles.yellow('⚠️  Warning: check your config'));
stdout.writeln(AnsiStyles.bold('dart_http — API request runner'));
stdout.writeln(AnsiStyles.cyan('→ GET https://api.example.com/users'));
</code></pre>
<p>Apply color intentionally and consistently:</p>
<ul>
<li><p><strong>Green</strong> — success states, completed operations</p>
</li>
<li><p><strong>Red</strong> — errors and failures</p>
</li>
<li><p><strong>Yellow</strong> — warnings and non-blocking issues</p>
</li>
<li><p><strong>Cyan</strong> — informational output, URLs, paths</p>
</li>
<li><p><strong>Bold</strong> — headers, tool names, important values</p>
</li>
</ul>
<p>Avoid coloring everything. Color loses meaning when it is everywhere. Use it to draw the user's eye to what actually matters.</p>
<h2 id="heading-testing-your-cli-tool">Testing Your CLI Tool</h2>
<p>CLI tools are testable, and they should be tested. The most reliable approach is to test the logic inside your commands directly — not the terminal output formatting, but the behaviour.</p>
<p>Add <code>test</code> to your dev dependencies if it's not already there:</p>
<pre><code class="language-yaml">dev_dependencies:
  test: ^1.24.0
</code></pre>
<p><strong>Testing command logic:</strong></p>
<pre><code class="language-dart">import 'package:test/test.dart';

import '../lib/models/task.dart';

void main() {
  group('Task model', () {
    test('copyWith updates isComplete correctly', () {
      final task = Task(
        id: 1,
        title: 'Write tests',
        priority: 'high',
        createdAt: DateTime.now(),
      );

      final completed = task.copyWith(isComplete: true);

      expect(completed.isComplete, isTrue);
      expect(completed.title, equals('Write tests'));
      expect(completed.id, equals(1));
    });

    test('toJson and fromJson round-trips correctly', () {
      final task = Task(
        id: 2,
        title: 'Ship the tool',
        priority: 'normal',
        createdAt: DateTime.parse('2025-01-01T00:00:00.000'),
      );

      final json = task.toJson();
      final restored = Task.fromJson(json);

      expect(restored.id, equals(task.id));
      expect(restored.title, equals(task.title));
      expect(restored.priority, equals(task.priority));
    });
  });
}
</code></pre>
<p><strong>Testing the headers parser:</strong></p>
<pre><code class="language-dart">import 'package:test/test.dart';

import '../lib/utils/headers_parser.dart';

void main() {
  group('parseHeaders', () {
    test('parses a single header correctly', () {
      final result = parseHeaders(['Authorization: Bearer mytoken']);
      expect(result['Authorization'], equals('Bearer mytoken'));
    });

    test('parses multiple headers', () {
      final result = parseHeaders([
        'Authorization: Bearer token',
        'Accept: application/json',
      ]);
      expect(result.length, equals(2));
      expect(result['Accept'], equals('application/json'));
    });

    test('ignores malformed headers without a colon', () {
      final result = parseHeaders(['malformed-header']);
      expect(result.isEmpty, isTrue);
    });
  });
}
</code></pre>
<p>Run your tests:</p>
<pre><code class="language-bash">dart test
</code></pre>
<h2 id="heading-deploying-and-distributing-your-cli">Deploying and Distributing Your CLI</h2>
<p>Building a CLI tool is half the work. Getting it into the hands of developers is the other half. There are five distribution paths available, each suited to a different use case.</p>
<h3 id="heading-mode-1-pubdev-public-package-distribution">Mode 1: pub.dev — Public Package Distribution</h3>
<p>Publishing to pub.dev makes your tool installable by anyone in the Dart and Flutter community with a single command.</p>
<h4 id="heading-prepare-your-package">Prepare your package:</h4>
<p>Your <code>pubspec.yaml</code> needs to be complete:</p>
<pre><code class="language-yaml">name: dart_http
description: A lightweight API request runner for Dart developers.
version: 1.0.0
homepage: https://github.com/yourname/dart_http

environment:
  sdk: '&gt;=3.0.0 &lt;4.0.0'

executables:
  dart_http: dart_http
</code></pre>
<p>The <code>executables</code> block is critical. It tells pub.dev which script in <code>bin/</code> to expose as a runnable command.</p>
<p>You also need:</p>
<ul>
<li><p><code>README.md</code> — what the tool does, how to install it, usage examples</p>
</li>
<li><p><code>CHANGELOG.md</code> — version history</p>
</li>
<li><p><code>LICENSE</code> — an open source license (MIT is standard)</p>
</li>
</ul>
<h4 id="heading-validate-before-publishing">Validate before publishing:</h4>
<pre><code class="language-bash">dart pub publish --dry-run
</code></pre>
<p>This runs all validation checks without actually publishing. Fix any warnings before proceeding.</p>
<h4 id="heading-publish">Publish:</h4>
<pre><code class="language-bash">dart pub publish
</code></pre>
<p>You will be prompted to authenticate with your pub.dev account. Once published, your tool is available globally:</p>
<pre><code class="language-bash">dart pub global activate dart_http
dart_http get https://api.example.com/users
</code></pre>
<h3 id="heading-mode-2-local-path-activation">Mode 2: Local Path Activation</h3>
<p>For internal team tools that you don't want to publish publicly, activate directly from a local or cloned repository:</p>
<pre><code class="language-bash">dart pub global activate --source path /path/to/dart_http
</code></pre>
<p>Any developer on the team clones the repo and runs this command once. The tool is then available globally in their terminal without needing a pub.dev publish.</p>
<p>This is the right distribution mode for:</p>
<ul>
<li><p>Internal company tooling</p>
</li>
<li><p>Tools that depend on private packages</p>
</li>
<li><p>Work-in-progress tools shared within a team before a public release</p>
</li>
</ul>
<h3 id="heading-mode-3-compiled-binary-via-github-releases">Mode 3: Compiled Binary via GitHub Releases</h3>
<p>Dart can compile to a self-contained native executable — no Dart SDK required on the target machine. This makes your tool accessible to developers outside the Dart ecosystem.</p>
<h4 id="heading-compile">Compile:</h4>
<pre><code class="language-bash"># macOS
dart compile exe bin/dart_http.dart -o dist/dart_http-macos

# Linux
dart compile exe bin/dart_http.dart -o dist/dart_http-linux

# Windows
dart compile exe bin/dart_http.dart -o dist/dart_http-windows.exe
</code></pre>
<p>The compiled binary is fully self-contained. Copy it to any machine and run it — no Dart installation needed.</p>
<h4 id="heading-automate-with-github-actions">Automate with GitHub Actions:</h4>
<p>Create <code>.github/workflows/release.yml</code>:</p>
<pre><code class="language-yaml">name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v3

      - uses: dart-lang/setup-dart@v1
        with:
          sdk: stable

      - name: Install dependencies
        run: dart pub get

      - name: Compile binary
        run: |
          mkdir -p dist
          dart compile exe bin/dart_http.dart -o dist/dart_http-${{ runner.os }}

      - name: Upload binary to release
        uses: softprops/action-gh-release@v1
        with:
          files: dist/dart_http-${{ runner.os }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
</code></pre>
<p>Every time you push a version tag (<code>v1.0.0</code>), GitHub Actions compiles binaries for all three platforms and attaches them to the GitHub Release automatically.</p>
<h4 id="heading-write-an-install-script">Write an install script:</h4>
<pre><code class="language-bash">#!/usr/bin/env bash
set -euo pipefail

VERSION="1.0.0"
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
BINARY="dart_http-$OS"
INSTALL_DIR="/usr/local/bin"

curl -L "https://github.com/yourname/dart_http/releases/download/v\(VERSION/\)BINARY" \
  -o "$INSTALL_DIR/dart_http"

chmod +x "$INSTALL_DIR/dart_http"
echo "dart_http installed successfully"
</code></pre>
<p>Developers install it with:</p>
<pre><code class="language-bash">curl -fsSL https://raw.githubusercontent.com/yourname/dart_http/main/install.sh | bash
</code></pre>
<h3 id="heading-mode-4-homebrew-tap">Mode 4: Homebrew Tap</h3>
<p>Homebrew is the standard package manager for macOS and is widely used on Linux. A Homebrew tap makes your tool installable with <code>brew install</code> — the most familiar installation pattern for macOS developers.</p>
<h4 id="heading-create-your-tap-repository">Create your tap repository:</h4>
<p>Create a new GitHub repository named <code>homebrew-tools</code> (the <code>homebrew-</code> prefix is required by Homebrew's naming convention).</p>
<h4 id="heading-write-the-formula">Write the formula:</h4>
<p>Create <code>Formula/dart_http.rb</code> in that repository:</p>
<pre><code class="language-ruby">class DartHttp &lt; Formula
  desc "A lightweight API request runner for the terminal"
  homepage "https://github.com/yourname/dart_http"
  version "1.0.0"

  on_macos do
    url "https://github.com/yourname/dart_http/releases/download/v1.0.0/dart_http-macOS"
    sha256 "YOUR_SHA256_HASH_HERE"
  end

  on_linux do
    url "https://github.com/yourname/dart_http/releases/download/v1.0.0/dart_http-Linux"
    sha256 "YOUR_SHA256_HASH_HERE"
  end

  def install
    bin.install "dart_http-#{OS.mac? ? 'macOS' : 'Linux'}" =&gt; "dart_http"
  end

  test do
    system "#{bin}/dart_http", "--help"
  end
end
</code></pre>
<p>Generate the SHA256 hash for each binary:</p>
<pre><code class="language-bash">shasum -a 256 dist/dart_http-macOS
</code></pre>
<h4 id="heading-install-from-the-tap">Install from the tap:</h4>
<pre><code class="language-bash">brew tap yourname/tools
brew install dart_http
</code></pre>
<p>When you release a new version, update the <code>url</code> and <code>sha256</code> values in the formula and push the change. Users run <code>brew upgrade dart_http</code> to update.</p>
<h3 id="heading-mode-5-docker">Mode 5: Docker</h3>
<p>Docker distribution is best suited for CI environments, teams that standardise on containers, or tools with complex dependencies.</p>
<h4 id="heading-write-a-dockerfile">Write a Dockerfile:</h4>
<pre><code class="language-dockerfile">FROM dart:stable AS build

WORKDIR /app
COPY pubspec.* ./
RUN dart pub get

COPY . .
RUN dart compile exe bin/dart_http.dart -o /app/dart_http

FROM debian:stable-slim
COPY --from=build /app/dart_http /usr/local/bin/dart_http

ENTRYPOINT ["dart_http"]
</code></pre>
<p>This uses a multi-stage build: the first stage compiles the binary using the Dart SDK image, and the second stage copies only the binary into a minimal Debian image. The final image has no Dart SDK — just the compiled binary.</p>
<h4 id="heading-build-and-run">Build and run:</h4>
<pre><code class="language-bash">docker build -t dart_http .
docker run dart_http get https://jsonplaceholder.typicode.com/users/1
</code></pre>
<h4 id="heading-publish-to-docker-hub">Publish to Docker Hub:</h4>
<pre><code class="language-bash">docker tag dart_http yourname/dart_http:1.0.0
docker push yourname/dart_http:1.0.0
</code></pre>
<p>Users can then run your tool without installing anything locally:</p>
<pre><code class="language-bash">docker run yourname/dart_http get https://api.example.com/users
</code></pre>
<h2 id="heading-choosing-the-right-distribution-mode">Choosing the Right Distribution Mode</h2>
<table>
<thead>
<tr>
<th>Mode</th>
<th>Best for</th>
<th>Dart SDK required</th>
</tr>
</thead>
<tbody><tr>
<td>pub.dev</td>
<td>Public Dart/Flutter developer tools</td>
<td>Yes</td>
</tr>
<tr>
<td>Local path activation</td>
<td>Internal team tools, pre-release builds</td>
<td>Yes</td>
</tr>
<tr>
<td>Compiled binary</td>
<td>Language-agnostic tools, broad adoption</td>
<td>No</td>
</tr>
<tr>
<td>Homebrew tap</td>
<td>macOS/Linux developer tools</td>
<td>No</td>
</tr>
<tr>
<td>Docker</td>
<td>CI environments, complex dependencies</td>
<td>No</td>
</tr>
</tbody></table>
<p>For most tools, the practical recommendation is:</p>
<ul>
<li><p>Start with <strong>pub.dev</strong> if your audience is Dart developers</p>
</li>
<li><p>Add <strong>compiled binary + GitHub Releases</strong> once you want broader adoption</p>
</li>
<li><p>Add a <strong>Homebrew tap</strong> when macOS developers start asking for it</p>
</li>
<li><p>Use <strong>Docker</strong> only when it is already part of your team's workflow</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You've gone from understanding what a CLI is to building three progressively complex tools and distributing them across five different channels.</p>
<p>The foundational skills – <code>args</code>, <code>stdin</code>, <code>stdout</code>, <code>stderr</code>, exit codes, file I/O, and process spawning – are the same building blocks that tools like <code>flutter</code>, <code>git</code>, and <code>dart</code> themselves are built on. Everything else is composition.</p>
<p>The three CLIs we built (Hello CLI, <code>dart_todo</code>, and <code>dart_http</code>) each introduced a new layer: raw Dart fundamentals, the <code>args</code> package with JSON persistence, and real-world HTTP interaction. The distribution section ensures that whatever you build next, you have a clear path to getting it in front of the developers who will use it.</p>
<p>Dart is a powerful language for CLI development. Its strong typing, async support, native compilation, and pub.dev ecosystem make it a serious choice for building developer tooling, not just mobile apps.</p>
<p>The next step is building something that solves a real problem for you or your team, and shipping it.</p>
<p>Happy coding!!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Integrate AI into Your Terminal Using OpenCode ]]>
                </title>
                <description>
                    <![CDATA[ Artificial intelligence is no longer just a helper, it’s becoming a real coding partner. Over the past year, developers have seen tools like GitHub Copilot and ChatGPT transform how code is written. But these tools mostly live in editors or browsers.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/integrate-ai-into-your-terminal-using-opencode/</link>
                <guid isPermaLink="false">68e8540e389372f3cb828525</guid>
                
                    <category>
                        <![CDATA[ terminal ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 10 Oct 2025 00:32:14 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760056302216/02783203-e22e-4f23-b5b9-2eae9523124c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Artificial intelligence is no longer just a helper, it’s becoming a real coding partner. Over the past year, developers have seen tools like GitHub Copilot and ChatGPT transform how code is written. But these tools mostly live in editors or browsers. </p>
<p><a target="_blank" href="http://opencode.ai/">OpenCode</a>, an open-source project, takes a different path. It brings an AI assistant directly into your terminal, letting you write, debug, and refactor code using natural language. All this without ever leaving the command line.</p>
<p>It combines the power of large language models with real-world developer workflows, so you can build software faster, with fewer distractions.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-opencode">What is OpenCode?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-use-opencode">Why Use OpenCode?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-opencode-works">How OpenCode Works</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-power-of-context">The Power of Context</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-privacy-and-control">Privacy and Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-real-world-use-cases">Real-World Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-community-and-ecosystem">Community and Ecosystem</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-future-of-ai-powered-development">The Future of AI-Powered Development</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-opencode">What is OpenCode?</h2>
<p>OpenCode is an open-source AI coding assistant that works right inside your terminal. It’s built for developers who prefer command-line speed but still want the intelligence of modern AI models. </p>
<p>You can think of it as having ChatGPT or Claude built into your local development environment, except it’s fully open and under your control.</p>
<p>Imagine typing a command like <code>opencode fix error in main.go</code>, and the AI instantly reads your code, finds the problem, and suggests a clean fix. That’s the magic of OpenCode.</p>
<p>The project is hosted at <a target="_blank" href="https://github.com/sst/opencode">github.com/sst/opencode</a> and has quickly become one of the most popular open-source AI tools for developers. As of October 2025, it has more than 26,000 stars on GitHub, proving that developers are hungry for coding tools that blend automation and simplicity.</p>
<h2 id="heading-why-use-opencode">Why Use OpenCode?</h2>
<p>Most AI coding assistants work inside editors like VS Code or JetBrains. OpenCode, on the other hand, lives in your terminal. This means it can work with any language, any editor, and any environment. </p>
<p>You can use it while building a backend in Go, a frontend in React, or even while managing infrastructure scripts.</p>
<p>OpenCode uses your project context to understand your code deeply. It scans through your files, recognizes dependencies, and maintains context across multiple commands. This allows it to perform complex operations like:</p>
<ul>
<li><p>Refactoring multiple files in one go</p>
</li>
<li><p>Adding new features based on natural language instructions</p>
</li>
<li><p>Explaining errors and suggesting fixes</p>
</li>
<li><p>Reviewing your code before you commit</p>
</li>
</ul>
<p>All of this happens without needing to upload your code to the cloud. Everything stays local, which is a major advantage for teams handling private or sensitive codebases.</p>
<h2 id="heading-how-opencode-works">How OpenCode Works</h2>
<p>OpenCode connects your local files, git history, and LLMs together. When you run a command like <code>opencode explain this function</code>, it gathers context from the files you’re working on, passes that to an AI model, and shows the response directly in your terminal.</p>
<p>The setup is simple. You can install OpenCode using a single command:</p>
<pre><code class="lang-plaintext">curl -fsSL https://opencode.ai/install | bash
</code></pre>
<p>Once installed, you can start using it by running:</p>
<pre><code class="lang-plaintext">opencode
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759742736177/89f883ae-fdfa-412c-a524-d72bcfab2138.png" alt="Opencode" class="image--center mx-auto" width="1000" height="475" loading="lazy"></p>
<p>The tool will open an interactive terminal interface where you can chat, run tasks, and even let the AI make edits automatically. It supports multiple model providers, including OpenAI, Anthropic, and local models like Ollama.</p>
<p>Behind the scenes, OpenCode uses a plugin-like architecture that makes it easy to extend. Developers can write “actions” or “skills” that teach the AI how to perform domain-specific tasks — like generating <a target="_blank" href="https://www.freecodecamp.org/news/learn-kubernetes-handbook-devs-startups-businesses/">Kubernetes</a> manifests, writing API routes, or setting up unit tests.</p>
<p>Once Opencode is installed, go to the project repository and type <code>opencode</code> . Then type <code>/init</code> for Opencode to analyze your repository and created <code>agents.md</code> file. </p>
<p>You can then start asking questions like “What does this repository do?”. Here is a sample output from my portfolio website.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759742758416/b9e560cb-88f9-4488-8bd0-0c4cd504ba0c.png" alt="Opencode project summary" class="image--center mx-auto" width="1000" height="255" loading="lazy"></p>
<p>You can use the the <a target="_blank" href="https://opencode.ai/docs">OpenCode documentation</a> to learn more tips and tricks to work with OpenCode. </p>
<h2 id="heading-the-power-of-context">The Power of Context</h2>
<p>One of OpenCode’s biggest strengths is how it handles context. Traditional chatbots lose track of what you’re working on after a few turns. OpenCode doesn’t. </p>
<p>OpenCode remembers your codebase, understands imports, and keeps track of related files. This allows it to work more like a real developer assistant.</p>
<p>Let’s say you tell it: <em>“Add authentication to my Express.js app.”</em></p>
<p>OpenCode will scan your project, identify where routes are defined, create middleware for login, and even suggest where to store tokens securely. It’s this blend of contextual awareness and natural language understanding that makes OpenCode feel more like a teammate than a tool.</p>
<h2 id="heading-privacy-and-control">Privacy and Control</h2>
<p>A major reason developers love OpenCode is control. Unlike cloud-based assistants, OpenCode doesn’t send your code to remote servers by default. </p>
<p>You choose the model provider and what data gets shared. If you run a local model, your entire workflow stays private.</p>
<p>This is especially important for companies with strict data rules. With OpenCode, teams can integrate AI safely into their workflows without breaking compliance or risking leaks.</p>
<p>The tool also integrates with version control systems like Git. Every change the AI suggests can be previewed before committing. You can accept, reject, or modify them just like a pull request. This ensures transparency and keeps human developers in charge.</p>
<h2 id="heading-real-world-use-cases">Real-World Use Cases</h2>
<p>Developers are using OpenCode in many creative ways. Backend engineers use it to generate API routes. Frontend teams use it to fix TypeScript errors. DevOps engineers rely on it to generate Terraform scripts and Dockerfiles.</p>
<p>Even researchers and students find it useful for exploring new codebases. By simply asking questions like “What does this repository do?” or “Where is the entry point?”, they can get clear, AI-driven summaries of complex projects.</p>
<p>The flexibility of OpenCode means it can fit almost any workflow. It doesn’t replace your tools , it enhances them. Whether you’re using Vim, VS Code, or JetBrains IDEs, OpenCode works alongside your setup.</p>
<h2 id="heading-community-and-ecosystem">Community and Ecosystem</h2>
<p>OpenCode is not just a tool, it’s a growing community. The project’s GitHub discussions and Discord are full of contributors sharing workflows, plugins, and even model configuration tips.</p>
<p>The maintainers, part of the SST team, are known for building tools that make cloud and AI development simpler. They continue to release frequent updates and listen closely to community feedback.</p>
<p>Recent updates have added features like persistent sessions, better error recovery, and support for local models. The roadmap includes plans for even deeper IDE integration and team collaboration features.</p>
<h2 id="heading-the-future-of-ai-powered-development">The Future of AI-Powered Development</h2>
<p>As AI coding agents mature, the line between writing code and describing what you want will continue to blur. Tools like OpenCode show us what that future might look like , one where developers spend less time fighting syntax and more time building ideas.</p>
<p>Imagine a day when you start a new project by typing: <em>“Create a REST API for a todo app with user authentication and SQLite support.”</em></p>
<p>And within seconds, your project structure, database, and routes are ready and reviewed by your AI assistant, tested, and documented.</p>
<p>That’s the vision OpenCode is moving toward: AI tools that don’t just generate code, but understand context, handle complexity, and let humans stay in control.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>OpenCode represents a turning point in how developers interact with AI. It’s open-source, private, and deeply integrated into the terminal, making it both powerful and flexible. While other assistants are built around specific IDEs or cloud services, OpenCode keeps developers at the center.</p>
<p>With its growing community, smart architecture, and commitment to privacy, OpenCode isn’t just another coding assistant. It’s a glimpse into the future of AI-driven software development, a future where your terminal becomes the smartest part of your workflow.</p>
<p><em>Hope you enjoyed this article. Signup for my free AI newsletter</em> <a target="_blank" href="https://www.turingtalks.ai/"><strong><em>TuringTalks.ai</em></strong></a> <em>for more hands-on tutorials on AI. You can also find</em> <a target="_blank" href="https://manishshivanandhan.com/"><strong><em>visit my website</em></strong></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is the GitHub CLI? How to Use GitHub from the Command Line ]]>
                </title>
                <description>
                    <![CDATA[ The GitHub CLI (Command Line Interface) is a powerful tool developed by GitHub that allows developers to interact with GitHub directly from the terminal. It provides a simple way to perform many GitHub tasks without leaving the command line interface... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-github-from-the-command-line/</link>
                <guid isPermaLink="false">68d6c4873324dabb31fd7214</guid>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ terminal ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ AYUSH MISHRA ]]>
                </dc:creator>
                <pubDate>Fri, 26 Sep 2025 16:51:19 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758905411969/b1506cff-650a-4098-bd70-e8bb3b0bcb9a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The GitHub CLI (Command Line Interface) is a powerful tool developed by GitHub that allows developers to interact with GitHub directly from the terminal. It provides a simple way to perform many GitHub tasks without leaving the command line interface, such as managing repositories, handling pull requests and issues, working with GitHub Actions, and more.</p>
<p>In this tutorial, you’ll to learn what the GitHub CLI is, how to install and set it up, and how to use it for everyday tasks such as creating repositories, managing issues and pull requests, working with GitHub Actions, and automating tasks using custom aliases. You’ll learn how to replace some functionalities on GitHub’s web interface with quick commands in your terminal.</p>
<h2 id="heading-heres-what-well-cover"><strong>Here’s what we’ll cover:</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-overview-of-github-cli">Overview of GitHub CLI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-features-of-github-cli">Key Features</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-benefits-of-using-github-cli">Benefits of Using GitHub CLI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-installation-and-setup">Installation and Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#authenticating-with-a-github-account">Authenticating with a GitHub Account</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-navigating-the-github-cli">Navigating the GitHub CLI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-manage-repositories-with-the-github-cli">Managing Repositories</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-managing-branches-and-pull-requests">Working with Pull Requests and Issues</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-pushing-and-pulling-changes">Pushing and Pulling Changes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-working-with-github-actions">Working with GitHub Actions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-manage-gists-with-the-github-cli">Managing Gists</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-interacting-with-releases-and-tags">Releases and Tags</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-extend-the-github-cli-with-custom-scripts-and-aliases">Custom Scripts and Aliases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-troubleshooting-common-issues">Troubleshooting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-overview-of-github-cli">Overview of GitHub CLI</h2>
<p>You can use the GitHub CLI to bridge the gap between GitHub's web interface and your local environment. You can perform various tasks such as creating issues, managing repositories, or even checking the status of your GitHub Actions workflows using the CLI. Using the CLI, you can perform almost all the tasks that you might complete on the GitHub website.</p>
<h3 id="heading-key-features-of-github-cli">Key Features of GitHub CLI</h3>
<ul>
<li><p><strong>Repository management:</strong> Easily create, clone, view, and manage repositories.</p>
</li>
<li><p><strong>Pull requests and issues:</strong> Manage pull requests and issues directly from the terminal, including creating, merging, and listing them.</p>
</li>
<li><p><strong>GitHub Actions:</strong> Interact with workflows and manage workflow runs.</p>
</li>
<li><p><strong>Authentication:</strong> Provides a secure way to authenticate with your GitHub account, supporting SSH keys, tokens, and OAuth.</p>
</li>
<li><p><strong>Custom scripting:</strong> Lets you create custom scripts and aliases to automate repetitive tasks and streamline development processes.</p>
</li>
</ul>
<h3 id="heading-benefits-of-using-github-cli">Benefits of Using GitHub CLI</h3>
<p>Suppose you’re working on a project, and you need to create a new issue on GitHub. Normally, you would switch to your browser, log in to GitHub, navigate to the repository, click on the “Issues” tab, and then click “New Issue.” With GitHub CLI, you can do all of this by typing a single command, without ever leaving your terminal. This makes your workflow faster and saves time.</p>
<h2 id="heading-installation-and-setup">Installation and Setup</h2>
<p>To install GitHub CLI on Windows, you can use the winget package manager. Winget is a command-line tool that allows you to install software easily.</p>
<h3 id="heading-installing-github-cli-on-windows-macos-and-linux"><strong>Installing GitHub CLI on Windows, macOS, and Linux</strong></h3>
<h3 id="heading-windows"><strong>Windows:</strong></h3>
<p>Run the command given below:</p>
<pre><code class="lang-plaintext">winget install --id GitHub.cli
</code></pre>
<ul>
<li><p><code>winget install</code><strong>:</strong> Tells Windows to install a new software package.</p>
</li>
<li><p><code>--id GitHub.cli</code><strong>:</strong> Specifies the exact package ID for GitHub CLI.</p>
</li>
</ul>
<p>After running this command, GitHub CLI will be installed on your Windows system.</p>
<h3 id="heading-macos">macOS:</h3>
<p>You can use Homebrew to install GitHub CLI on macOS. Open your terminal and run:</p>
<pre><code class="lang-plaintext">brew install gh
</code></pre>
<h3 id="heading-linux">Linux:</h3>
<p>On Linux, you can use your package manager. For example, on Ubuntu, you can run:</p>
<pre><code class="lang-plaintext">sudo apt install gh
</code></pre>
<h3 id="heading-authenticating-with-a-github-account">Authenticating with a GitHub Account</h3>
<p>After installing GitHub CLI, the next step is to authenticate it with your GitHub account.</p>
<h4 id="heading-run-authentication-command">Run Authentication Command:</h4>
<p>Type <code>gh auth login</code> in the terminal and press Enter.</p>
<pre><code class="lang-plaintext">gh auth login
</code></pre>
<p>You’ll then be prompted to select an authentication method. The recommended option is to authenticate via a web browser.</p>
<p>If you select the browser method, GitHub CLI will open a link in your default browser, where you can log in to GitHub.</p>
<h4 id="heading-complete-authentication">Complete Authentication:</h4>
<p>After logging in, the browser will confirm that the GitHub CLI is connected to your account.</p>
<p>You can verify the authentication status by running:</p>
<pre><code class="lang-plaintext">gh auth status
</code></pre>
<h2 id="heading-navigating-the-github-cli">Navigating the GitHub CLI</h2>
<p>The GitHub CLI is easy to navigate, and its command structure is intuitive.</p>
<h3 id="heading-command-structure-and-syntax">Command Structure and Syntax</h3>
<p>GitHub CLI commands follow a simple and straightforward pattern:</p>
<pre><code class="lang-plaintext">gh [command] [subcommand] [flags]
</code></pre>
<ul>
<li><p><strong>Command:</strong> The main action you want to perform (for example, repo, issue, pr).</p>
</li>
<li><p><strong>Subcommand:</strong> A specific task within the command (for example, create, list, view).</p>
</li>
<li><p><strong>Flags:</strong> Optional parameters that modify the command's behavior (for example, --title, --body).</p>
</li>
</ul>
<h3 id="heading-commonly-used-commands-and-flags">Commonly Used Commands and Flags</h3>
<p>Here are some common GitHub CLI commands:</p>
<ul>
<li><p><strong>Creating a repository:</strong> <code>gh repo create</code></p>
</li>
<li><p><strong>Listing issues:</strong> <code>gh issue list</code></p>
</li>
<li><p><strong>Creating a pull request:</strong> <code>gh pr create</code></p>
</li>
<li><p><strong>Viewing a repository's details:</strong> <code>gh repo view</code></p>
</li>
</ul>
<p>To see all available commands and options, you can always run:</p>
<pre><code class="lang-plaintext">gh help
</code></pre>
<h2 id="heading-how-to-manage-repositories-with-the-github-cli">How to Manage Repositories with the GitHub CLI</h2>
<p>Let’s go through examples of some of the commands you’ll use the most often.</p>
<h3 id="heading-creating-and-cloning-repositories">Creating and Cloning Repositories</h3>
<p>To create a new GitHub repository directly from the terminal, just use the following command:</p>
<pre><code class="lang-plaintext">gh repo create my-repo-name
</code></pre>
<p>To clone an existing repository, use the following command:</p>
<pre><code class="lang-plaintext">gh repo clone owner/repo-name
</code></pre>
<h3 id="heading-managing-branches-and-pull-requests">Managing Branches and Pull Requests</h3>
<p>GitHub CLI allows you to handle issues and pull requests (PRs) without leaving the terminal.</p>
<p>Switching branches or creating pull requests is simple. To create a new branch:</p>
<pre><code class="lang-plaintext">git checkout -b new-branch-name
</code></pre>
<p>Then, to create a pull request:</p>
<pre><code class="lang-plaintext">gh pr create --title "Your PR Title" --body "Description of your PR"
</code></pre>
<h3 id="heading-pushing-and-pulling-changes">Pushing and Pulling Changes</h3>
<p>Push your changes to GitHub with this command:</p>
<pre><code class="lang-plaintext">git push origin branch-name
</code></pre>
<p>And pull the latest changes with:</p>
<pre><code class="lang-plaintext">git pull
</code></pre>
<h3 id="heading-working-with-github-actions">Working with GitHub Actions</h3>
<p>GitHub CLI also supports GitHub Actions, allowing you to manage workflows directly from your terminal.</p>
<p>You can manually trigger workflows using the following:</p>
<pre><code class="lang-plaintext">gh workflow run workflow-name
</code></pre>
<p>And you can monitor the status of workflows with:</p>
<pre><code class="lang-plaintext">gh run list
</code></pre>
<p>To see detailed logs of a workflow, run this:</p>
<pre><code class="lang-plaintext">gh run view run-id --log
</code></pre>
<h3 id="heading-cloning-and-forking-repositories">Cloning and Forking Repositories</h3>
<p>Cloning and forking are essential tasks when working on projects from other repositories.</p>
<p>To clone a repository, use this command:</p>
<pre><code class="lang-plaintext">gh repo clone &lt;repository-name&gt;
</code></pre>
<p>To fork a repository, do this:</p>
<pre><code class="lang-plaintext">gh repo fork &lt;repository-url&gt;
</code></pre>
<h4 id="heading-example"><strong>Example:</strong></h4>
<p>Here’s what it would look like:</p>
<pre><code class="lang-plaintext">gh repo clone example-repo
</code></pre>
<pre><code class="lang-plaintext">gh repo fork https://github.com/username/repository-name
</code></pre>
<h3 id="heading-how-to-work-with-github-actions">How to Work with GitHub Actions</h3>
<p>Using the GitHub CLI, you can also manage GitHub Actions, which are automated tasks you can run in response to certain events in your repository.</p>
<h4 id="heading-triggering-and-monitoring-workflows">Triggering and Monitoring Workflows</h4>
<p>You can trigger a workflow manually like this:</p>
<pre><code class="lang-plaintext">gh workflow run &lt;workflow-name&gt;
</code></pre>
<p>And you can monitor workflow runs with this:</p>
<pre><code class="lang-plaintext">gh run list
</code></pre>
<h4 id="heading-managing-workflow-runs-and-logs">Managing Workflow Runs and Logs</h4>
<p>If you want to check the details of a specific workflow run, you can view logs directly from the CLI:</p>
<pre><code class="lang-plaintext">gh run view &lt;run-id&gt; --log
</code></pre>
<p>You can also use GitHub CLI commands to enhance your Continuous Integration/Continuous Deployment (CI/CD) pipelines, ensuring smooth automation and better control over our workflows.</p>
<h3 id="heading-how-to-update-the-github-cli">How to Update the GitHub CLI</h3>
<p>To make sure that you’re using the latest version of GitHub CLI with all the latest features and fixes, you can update it using winget.</p>
<pre><code class="lang-plaintext">winget upgrade --id GitHub.cli
</code></pre>
<ul>
<li><p><strong>winget upgrade:</strong> Checks for updates for the specified package.</p>
</li>
<li><p><strong>--id GitHub.cli:</strong> Identifies the GitHub CLI package for the upgrade.</p>
</li>
</ul>
<h2 id="heading-advanced-github-cli-features-and-integrations">Advanced GitHub CLI Features and Integrations</h2>
<p>The GitHub CLI is not only useful for performing basic tasks. You can also perform some advanced operations with its help.</p>
<h3 id="heading-how-to-manage-gists-with-the-github-cli">How to Manage Gists with the GitHub CLI</h3>
<p>Gists are a simple way to share snippets of code. You can create, list, and manage your Gists right from the CLI. Here’s how you can create a gist:</p>
<pre><code class="lang-plaintext">gh gist create my-code-snippet.py
</code></pre>
<p>To list your gists:</p>
<pre><code class="lang-plaintext">gh gist list
</code></pre>
<h3 id="heading-interacting-with-releases-and-tags">Interacting with Releases and Tags</h3>
<p>To manage releases and tags, GitHub CLI provides commands to create, list, and delete releases. Here’s an example of creating a release:</p>
<pre><code class="lang-plaintext">gh release create v1.0.0
</code></pre>
<h3 id="heading-how-to-extend-the-github-cli-with-custom-scripts-and-aliases">How to Extend the GitHub CLI with Custom Scripts and Aliases</h3>
<p>You can write your own scripts and integrate them into GitHub CLI, or create aliases for commands you use frequently to save time. Aliases let you create shortcuts for commands that you use often. For example, the command given below creates an alias <code>prlist</code> that will show all pull requests, regardless of their state:</p>
<pre><code class="lang-plaintext">gh alias set prlist "pr list --state all"
</code></pre>
<p>In the same manner, you can create a shortcut <code>co</code> to quickly check out a pull request branch without typing the full command each time. The command is given below:</p>
<pre><code class="lang-plaintext">gh alias set co "pr checkout"
</code></pre>
<h3 id="heading-troubleshooting-common-issues">Troubleshooting Common Issues</h3>
<p>If you face any issues, you can troubleshoot by checking the command syntax, ensuring your GitHub CLI is up to date, or consulting the documentation using the command:</p>
<pre><code class="lang-plaintext">gh help &lt;command&gt;
</code></pre>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>GitHub CLI is an excellent tool that helps developers work directly from the terminal. It lets you manage repositories, handle pull requests and issues, trigger and monitor GitHub Actions, and even work with Gists.</p>
<p>You can save time and improve productivity as developers using this powerful tool. Keep exploring its new features and stay updated with the latest version.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Essential CLI/TUI Tools for Developers ]]>
                </title>
                <description>
                    <![CDATA[ As developers, we spend a lot of time in our terminals. And there are tons of great CLI/TUI tools that can boost our productivity (as well as some that are just fun to use). From managing Git repositories and navigating file systems to monitoring sys... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/essential-cli-tui-tools-for-developers/</link>
                <guid isPermaLink="false">6798fd7b4666e531b7dd7586</guid>
                
                    <category>
                        <![CDATA[ terminal ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cli ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Pliutau ]]>
                </dc:creator>
                <pubDate>Tue, 28 Jan 2025 15:53:31 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738077620615/22e3c744-d609-4469-ae10-ef8ad4b515a1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As developers, we spend a lot of time in our terminals. And there are tons of great CLI/TUI tools that can boost our productivity (as well as some that are just fun to use). From managing Git repositories and navigating file systems to monitoring system performance and even playing retro games, the command line offers a powerful and versatile environment.</p>
<p>In this article, we’ll go through a collection of CLI / TUI tools that have been widely adopted in the developer community, spanning various categories such as version control, system utilities, text editors, and more. I wanted to give you a diverse selection that caters to different needs and workflows.</p>
<p>For each tool, I’ll include an overview, highlighting its key features and use cases, along with clear and concise installation instructions for various operating systems, ensuring you can quickly get up and running with these valuable command-line companions.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-kubernetes-tools">Kubernetes Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-container-tools">Container Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-file-and-text-tools">File and Text Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-git-tools">Git Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-development-tools">Development Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-networking-tools">Networking Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-workstation-tools">Workstation Tools</a></p>
</li>
</ul>
<h2 id="heading-kubernetes-tools"><strong>Kubernetes Tools</strong></h2>
<h3 id="heading-k9shttpsgithubcomderailedk9s-kubernetes-cli-to-manage-your-clusters-in-style"><a target="_blank" href="https://github.com/derailed/k9s"><strong>k9s</strong></a> — Kubernetes CLI To Manage Your Clusters In Style</h3>
<p>K9s is a must-have tool for anyone working with Kubernetes. Its intuitive terminal-based UI, real-time monitoring capabilities, and powerful command options make it a standout in the world of Kubernetes management tools.</p>
<p>The K9s project is designed to continually watch Kubernetes cluster for changes and offer subsequent commands to interact with observed resources. This makes it easier to manage applications, especially in a complex, multi-cluster environment. The project’s aim is to make Kubernetes management more accessible and less daunting, especially for those who are not Kubernetes experts.</p>
<p>Just launch k9s in your terminal and start exploring the Kubernetes resources with ease.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*tkfwKS01NCnUBE-N.png" alt="K9s interface" width="700" height="367" loading="lazy"></p>
<p>To install K9s:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install derailed/k9s/k9s

<span class="hljs-comment"># via snap for Linux</span>
snap install k9s --devmode

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install k9s

<span class="hljs-comment"># via go install</span>
go install github.com/derailed/k9s@latest
</code></pre>
<h3 id="heading-kubectxhttpsgithubcomahmetbkubectx-switch-between-contexts-clusters-on-kubectl-faster"><a target="_blank" href="https://github.com/ahmetb/kubectx"><strong>kubectx</strong></a> — switch between contexts (clusters) on kubectl faster.</h3>
<p>Kubectx is the most popular tool for switching Kubernetes contexts, but it has the fewest features! It displays all the contexts in your Kubernetes config as a selectable list and lets you pick one. That’s it!</p>
<p>This project comes with 2 tools:</p>
<ul>
<li><p><strong>kubectx</strong> is a tool that helps you switch between contexts (clusters) on kubectl faster.</p>
</li>
<li><p><strong>kubens</strong> is a tool to switch between Kubernetes namespaces (and configure them for kubectl) easily.</p>
</li>
</ul>
<p>These tools make it very easy to switch between Kubernetes clusters and namespaces if you work with many of them daily. Here you can see it in action:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*g442WF-cXW-z1dKQ.gif" alt="0*g442WF-cXW-z1dKQ" width="1367" height="472" loading="lazy"></p>
<p>To install kubectx:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install kubectx

<span class="hljs-comment"># via apt for Debian</span>
sudo apt install kubectx

<span class="hljs-comment"># via pacman for Arch Linux</span>
sudo pacman -S kubectx

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install kubens kubectx
</code></pre>
<h3 id="heading-kubescapehttpsgithubcomkubescapekubescape-kubernetes-security-platform-for-your-ide-cicd-pipelines-and-clusters"><a target="_blank" href="https://github.com/kubescape/kubescape"><strong>kubescape</strong></a> — Kubernetes security platform for your IDE, CI/CD pipelines, and clusters.</h3>
<p>I hope you take the security of your Kubernetes clusters seriously. If so, <strong>kubescape</strong> is really great for testing if your Kubernetes cluster is deployed securely according to multiple frameworks.</p>
<p>Kubescape can scan clusters, YAML files, and Helm charts and detects the misconfigurations according to multiple sources.</p>
<p>I usually use it in my CI/CD to scan for vulnerabilities automatically when changing Kubernetes manifests or Helm templates.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*Ft2r01ij9Rxj2-V0.png" alt="kubescape scan" width="700" height="556" loading="lazy"></p>
<p>To install kubescape:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install kubescape

<span class="hljs-comment"># via apt for Debian</span>
sudo add-apt-repository ppa:kubescape/kubescape
sudo apt update
sudo apt install kubescape

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install kubescape
</code></pre>
<h2 id="heading-container-tools"><strong>Container Tools</strong></h2>
<h3 id="heading-ctophttpsgithubcombcicenctop-a-top-like-interface-for-container-metrics"><a target="_blank" href="https://github.com/bcicen/ctop"><strong>ctop</strong></a> — A top-like interface for container metrics.</h3>
<p><strong>ctop</strong> is basically a better version of <code>docker stats</code>. It provides a concise and condensed overview of real-time metrics for multiple containers. It comes with built-in support for Docker and runC, and connectors for other container and cluster systems are planned for future releases.</p>
<p>Using ctop is simple. Once you have the tool open, you’ll see all of your currently active containers listed.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*EJ5kdlEs5M5QxDBy.gif" alt="ctop in action" width="1195" height="414" loading="lazy"></p>
<p>To install ctop:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install ctop

<span class="hljs-comment"># via pacman for Arch Linux</span>
sudo pacman -S ctop

<span class="hljs-comment"># via scoop for Windows</span>
scoop install ctop
</code></pre>
<h3 id="heading-lazydockerhttpsgithubcomjesseduffieldlazydocker-a-simple-terminal-ui-for-both-docker-and-docker-compose"><a target="_blank" href="https://github.com/jesseduffield/lazydocker"><strong>lazydocker</strong></a> — A simple terminal UI for both docker and docker-compose.</h3>
<p>While Docker's command-line interface is powerful, sometimes you might want a more visual approach without the overhead of a full GUI. This is especially true when managing Docker containers on a headless Linux server where installing a web-based GUI might be undesirable.</p>
<p>Lazydocker was created by <a target="_blank" href="https://github.com/jesseduffield">Jesse Duffield</a> to help make <a target="_blank" href="https://github.com/jesseduffield"></a>managing docker containers a bit easier. Simply put, Lazydocker is a terminal UI (written in Golang) for the docker and docker-compose commands.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*Cbmx4ShRSO7ccVy2.gif" alt="lazydocker in action" width="1456" height="819" loading="lazy"></p>
<p>To install lazydocker:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install lazydocker

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install lazydocker

<span class="hljs-comment"># via go install</span>
go install github.com/jesseduffield/lazydocker@latest
</code></pre>
<h3 id="heading-divehttpsgithubcomwagoodmandive-a-tool-for-exploring-each-layer-in-a-docker-image"><a target="_blank" href="https://github.com/wagoodman/dive"><strong>dive</strong></a> — A tool for exploring each layer in a Docker image.</h3>
<p>A Docker image is made up of layers, and with every layer you add on, more space will be taken up by the image. Therefore, the more layers in the image, the more space the image will require.</p>
<p>That’s where <strong>dive</strong> shines, it helps you explore your Docker image and layer contents. It can also help you find ways to shrink the size of your Docker/OCI image.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*swo_hrKJ9EV7hyMs.gif" alt="0*swo_hrKJ9EV7hyMs" width="1456" height="909" loading="lazy"></p>
<p>To install dive:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install dive

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -S dive

<span class="hljs-comment"># via go install</span>
go get github.com/wagoodman/dive
</code></pre>
<h2 id="heading-file-and-text-tools"><strong>File and Text Tools</strong></h2>
<h3 id="heading-jqhttpsgithubcomjqlangjq-command-line-json-processor"><a target="_blank" href="https://github.com/jqlang/jq"><strong>jq</strong></a> — Command-line JSON processor.</h3>
<p>You may be aware of this one already as it’s well known in the developer community.</p>
<p>Unfortunately, shells such as Bash can’t interpret and work with JSON directly. That’s where you can use <strong>jq</strong> as a command-line JSON processor that’s similar to sed, awk, grep, and so on for JSON data. It’s written in portable C and doesn’t have any runtime dependencies. This lets you slice, filter, map, and transform structured data with ease.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*uwysqWprpmrLrJQP.png" alt="0*uwysqWprpmrLrJQP" width="700" height="328" loading="lazy"></p>
<p>To install jq, you can download the latest releases from the <a target="_blank" href="https://github.com/jqlang/jq/releases">GitHub release page.</a></p>
<h3 id="heading-bathttpsgithubcomsharkdpbat-a-cat1-clone-with-wings"><a target="_blank" href="https://github.com/sharkdp/bat"><strong>bat</strong></a> — A cat(1) clone with wings.</h3>
<p>This is the most used CLI on my machine currently. A few years ago it was <strong>cat</strong>, which is great but doesn’t provide syntax highlighting, or Git integration</p>
<p>Bat’s syntax highlighting supports many programming and markup languages, helping you make your code more readable directly in the terminal. Git integration lets you see modifications in relation to the index, highlighting the lines you’ve added or changed.</p>
<p>Simply run <code>bat filename</code> and enjoy its output.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:656/0*L02HhsqDcq2_G_z4.png" alt="Bat example" width="656" height="450" loading="lazy"></p>
<p>To install bat:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install bat

<span class="hljs-comment"># via apt for Debian</span>
sudo apt install bat

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -S bat

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install bat
</code></pre>
<h3 id="heading-ripgrephttpsgithubcomburntsushiripgrep-recursively-search-directories-for-a-regex-pattern-while-respecting-your-gitignore"><a target="_blank" href="https://github.com/BurntSushi/ripgrep"><strong>ripgrep</strong></a> — Recursively search directories for a regex pattern while respecting your gitignore.</h3>
<p><strong>ripgrep</strong> is definitely becoming a popular alternative (if not the most popular) to the <strong>grep</strong> command. Even some editors like <a target="_blank" href="https://code.visualstudio.com/updates/v1_11">Visual Studio Code</a> are using ripgrep to power their search offerings.</p>
<p>The major selling point is its default behavior for recursive search and speed.</p>
<p>I now rarely use grep on my personal machine, as ripgrep is much faster.</p>
<p>To install ripgrep:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install ripgrep

<span class="hljs-comment"># via apt for Debian</span>
sudo apt-get install ripgrep

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -S ripgrep

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install ripgrep
</code></pre>
<h2 id="heading-git-tools"><strong>Git Tools</strong></h2>
<h3 id="heading-lazygithttpsgithubcomjesseduffieldlazygit-simple-terminal-ui-for-git-commands"><a target="_blank" href="https://github.com/jesseduffield/lazygit"><strong>lazygit</strong></a> — Simple terminal UI for git commands.</h3>
<p><strong>lazygit</strong> is another great terminal UI for Git commands developed by <a target="_blank" href="https://github.com/jesseduffield"><strong>Jesse Duffield</strong></a> using Go.</p>
<p>I don’t mind using the Git CLI directly for simple things, but it is famously verbose for more advanced use cases. I am just too lazy to memorize longer commands.</p>
<p>And lazigit has made me a more productive Git user than ever.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*ykEtn2HQ9QgU40jx.png" alt="lazygit interface" width="700" height="381" loading="lazy"></p>
<p>To install lazygit:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install jesseduffield/lazygit/lazygit

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -S lazygit

<span class="hljs-comment"># via scoop for Windows</span>
scoop install lazygit
</code></pre>
<h2 id="heading-development-tools"><strong>Development Tools</strong></h2>
<h3 id="heading-atachttpsgithubcomjulien-cpsnatac-a-simple-api-client-postman-like-in-your-terminal"><a target="_blank" href="https://github.com/Julien-cpsn/ATAC"><strong>ATAC</strong></a> — A simple API client (Postman-like) in your terminal.</h3>
<p>ATAC stands for Arguably a Terminal API Client. It’s based on popular clients like Postman, Insomnia, and Bruno, but it runs inside your terminal without needing any particular graphical environment.</p>
<p>It works best for developers who need an offline, cross-platform API client right at their fingertips (terminal).</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*NoOMeMxkELNFI9RS.png" alt="ATAC" width="700" height="376" loading="lazy"></p>
<p>To install ATAC:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew tap julien-cpsn/atac
brew install atac

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -S atac
</code></pre>
<h3 id="heading-k6httpsgithubcomgrafanak6-a-modern-load-testing-tool-using-go-and-javascript"><a target="_blank" href="https://github.com/grafana/k6"><strong>k6</strong></a> — A modern load testing tool, using Go and JavaScript.</h3>
<p>I’ve used many load-testing tools in my career, such as <a target="_blank" href="https://github.com/tsenart/vegeta">vegeta</a> or even <a target="_blank" href="https://httpd.apache.org/docs/2.4/programs/ab.html">ab</a> in the past. But now I mostly use <strong>k6s</strong> as it has everything I need and has a great GUI and TUI.</p>
<p>Why it works well for me:</p>
<ul>
<li><p>k6 has really good <a target="_blank" href="https://k6.io/docs/">documentation</a></p>
</li>
<li><p>Many integrations available: Swagger, JMeter scripts, and so on.</p>
</li>
<li><p>Results reporting is quite good</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737552000859/df5af273-3706-4d41-9dbe-717d2f2d18b7.webp" alt="K6 interface" class="image--center mx-auto" width="1698" height="1184" loading="lazy"></p>
<p>To install k6:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install k6

<span class="hljs-comment"># via apt for Debian</span>
sudo apt-get install k6

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install k6
</code></pre>
<h3 id="heading-httpiehttpsgithubcomhttpiecli-modern-user-friendly-command-line-http-client-for-the-api-era"><a target="_blank" href="https://github.com/httpie/cli"><strong>httpie</strong></a> — modern, user-friendly command-line HTTP client for the API era.</h3>
<p>Don’t get me wrong, curl is great, but not very human-friendly.</p>
<p>HTTPie has a simple and expressive syntax, supports JSON and form data, handles authentication and headers, and displays colorized and formatted output.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*Bqi3gBKgIkeEPEI_.gif" alt="0*Bqi3gBKgIkeEPEI_" width="1024" height="512" loading="lazy"></p>
<p>To install httpie:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install httpie

<span class="hljs-comment"># via apt for Debian</span>
sudo apt install httpie

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -Syu httpie

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install httpie
</code></pre>
<h3 id="heading-asciinemahttpsgithubcomasciinemaasciinema-terminal-session-recorder"><a target="_blank" href="https://github.com/asciinema/asciinema"><strong>asciinema</strong></a> — Terminal session recorder.</h3>
<p>I call it a terminal YouTube :)</p>
<p>asciinema is a great tool when you want to share your terminal sessions with someone else, instead of recording heavy videos.</p>
<p>I use it often when I develop some CLI tools and want to share the demo of how they work (on GitHub, for example).</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*Exg2XuZlIPaJJ-iB.png" alt="0*Exg2XuZlIPaJJ-iB" width="700" height="389" loading="lazy"></p>
<p>To install asciinema:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install asciinema

<span class="hljs-comment"># via apt for Debian</span>
sudo apt install asciinema

<span class="hljs-comment"># via pacman for Arch Linux</span>
sudo pacman -S asciinema
</code></pre>
<h2 id="heading-networking"><strong>Networking</strong></h2>
<h3 id="heading-doggohttpsgithubcommr-karandoggo-a-command-line-dns-client"><a target="_blank" href="https://github.com/mr-karan/doggo">doggo</a> — A command-line DNS client.</h3>
<p>It's totally inspired by <strong>dog</strong> which is written in Rust.</p>
<p>In the past I would use <strong>dig</strong> to inspect the DNS, but its output is often verbose and difficult to parse visually.</p>
<p><strong>doggo</strong> addresses these shortcomings by offering two key improvements:</p>
<ul>
<li><p>doggo provides the JSON output support for easy scripting and parsing.</p>
</li>
<li><p>doggo offers a human-readable output format that uses color-coding and a tabular layout to present DNS information clearly and concisely.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737552264803/bb902365-bc0d-4a56-9a87-6b065ee5608a.png" alt="bb902365-bc0d-4a56-9a87-6b065ee5608a" class="image--center mx-auto" width="3680" height="2572" loading="lazy"></p>
<p>To install doggo:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install doggo

<span class="hljs-comment"># via scoop for Windows</span>
scoop install doggo

<span class="hljs-comment"># via go install</span>
go install github.com/mr-karan/doggo/cmd/doggo@latest
</code></pre>
<h3 id="heading-gpinghttpsgithubcomorfgping-ping-but-with-a-graph"><a target="_blank" href="https://github.com/orf/gping"><strong>gping</strong></a> — Ping, but with a graph.</h3>
<p>The well-known <strong>ping</strong> command is not the most interesting to look at, and interpreting its output in a useful way can be difficult.</p>
<p><strong>gping</strong> gives a plot of the ping latency to a host, and the most useful feature is the ability to run concurrent pings to multiple hosts and plot all of them on the same graph.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*IPi1TOpiMnWPN1VU.gif" alt="0*IPi1TOpiMnWPN1VU" width="1411" height="757" loading="lazy"></p>
<p>To install gping:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install gping

<span class="hljs-comment"># via Chocolatey for Windows</span>
choco install gping

<span class="hljs-comment"># via apt for Debian</span>
apt install gping
</code></pre>
<h2 id="heading-workstation"><strong>Workstation</strong></h2>
<h3 id="heading-tmuxhttpsgithubcomtmuxtmuxwiki-a-terminal-multiplexer"><a target="_blank" href="https://github.com/tmux/tmux/wiki"><strong>tmux</strong></a> — A terminal multiplexer.</h3>
<p>Why is tmux such a big deal?</p>
<p>You may have run into situations where you need to view multiple terminal consoles at the same time. For example, you may have a few servers running (for example, web, database, debugger) and you might want to monitor all the output coming from these servers in real-time to validate behavior or run commands.</p>
<p>Before tmux, you might have just opened a few different tabs in the terminal and switched between them to see the output.</p>
<p>Thankfully, there’s an easier way — <strong>tmux</strong>.</p>
<p>In a nutshell, here are some of its most popular features:</p>
<ul>
<li><p>Window/Pane management</p>
</li>
<li><p>Session management with persistence</p>
</li>
<li><p>Sharable sessions with other users</p>
</li>
<li><p>Scriptable configurations</p>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*u8o0WxutrPXxg6FG.png" alt="0*u8o0WxutrPXxg6FG" width="700" height="294" loading="lazy"></p>
<p>To install tmux:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install tmux

<span class="hljs-comment"># via apt for Debian</span>
apt install tmux

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -S tmux
</code></pre>
<h3 id="heading-zellijhttpsgithubcomzellij-orgzellij-a-terminal-workspace-with-batteries-included"><a target="_blank" href="https://github.com/zellij-org/zellij"><strong>zellij</strong></a> — A terminal workspace with batteries included.</h3>
<p>Since I listed tmux here, it also makes sense to include a new competitor, <strong>Zellij</strong>, which has been gaining traction in the developer community. Both have their own unique features and purposes.</p>
<p>Compared to traditional terminal multiplexers, zellij offers a more user-friendly interface, modern design elements, built-in layout systems, and a plugin system, making it easier for newcomers to get started.</p>
<p>I still like tmux. It has a special place in my heart because it has served a great purpose for years. But zellij is another good option.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*VwAit4tO1IjxH9dp.gif" alt="0*VwAit4tO1IjxH9dp" width="825" height="435" loading="lazy"></p>
<p>To install zellij:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install zellij

<span class="hljs-comment"># via apt for Debian</span>
apt install zellij

<span class="hljs-comment"># via pacman for Arch Linux</span>
pacman -S zellij
</code></pre>
<h3 id="heading-btophttpsgithubcomaristocratosbtop-a-monitor-of-resources"><a target="_blank" href="https://github.com/aristocratos/btop"><strong>btop</strong></a> — A monitor of resources.</h3>
<p>I can’t live without btop, and it’s installed on all my machines via my personal <a target="_blank" href="https://github.com/plutov/dotfiles">dotfiles</a>. I rarely use now built-in OS GUIs to check the resource utilization on my host machine, because <strong>btop</strong> can do it much better.</p>
<p>I use to to quickly explore what uses the most memory, monitor and kill some processes, and more.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/0*HbuJrCbT6xVApLoh.png" alt="0*HbuJrCbT6xVApLoh" width="700" height="441" loading="lazy"></p>
<p>To install btop:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># via Homebrew for macOS</span>
brew install btop

<span class="hljs-comment"># via snap for Debian</span>
sudo snap install btop
</code></pre>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>These CLIs/TUIs should work well in any modern terminal. I personally use <a target="_blank" href="https://ghostty.org/">Ghostty</a> currently and it works great, but other popular options like <strong>iTerm2, Kitty</strong>, and the default terminal applications on macOS and Linux should also provide a seamless experience. The key is to ensure your terminal supports features like 256-color palettes and UTF-8 encoding for optimal display of these tools.</p>
<p>There’s a huge amount of CLIs/TUIs out there, and I couldn’t list them all (though I tried to list some of the best). This selection represents a starting point for exploring the rich ecosystem of command-line tools available to developers. I encourage you to explore further, discover new tools that fit your specific needs, and contribute back to the community by sharing your findings.</p>
<p><a target="_blank" href="https://packagemain.tech">Explore more articles on packagemain.tech</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Piping and Redirection in the Linux Terminal ]]>
                </title>
                <description>
                    <![CDATA[ The command line interface in Linux provides a powerful way of perfoming a range of tasks on your system. Because of its roots, Linux has many features baked into the terminal. Two of these powerful features are piping and redirection. These features... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/linux-terminal-piping-and-redirection-guide/</link>
                <guid isPermaLink="false">66c4c469bd556981b1bdc44b</guid>
                
                    <category>
                        <![CDATA[ Bash ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ terminal ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alvin ]]>
                </dc:creator>
                <pubDate>Fri, 26 Apr 2024 23:15:26 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/piping-redirection-linux.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The command line interface in Linux provides a powerful way of perfoming a range of tasks on your system. Because of its roots, Linux has many features baked into the terminal.</p>
<p>Two of these powerful features are piping and redirection. These features enable you to redirect the output and input of commands to and from other commands and files.</p>
<p>In this article, you'll learn what piping and redirection in Linux mean, followed by a deep dive into how to use these features yourself.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To fully understand this guide, you'll need to at least have:</p>
<ul>
<li>Basic <a target="_blank" href="https://www.freecodecamp.org/news/learn-the-basics-of-the-linux-operating-system">understanding of the Linux operating system</a>.</li>
<li>Basic experience working with the Linux command line. </li>
<li>Access to a Linux command line to try out the commands.</li>
</ul>
<p>Take a look at this <a target="_blank" href="https://www.freecodecamp.org/news/linux-command-line-tutorial/">Linux command line tutorial</a> if you're new or need a refresher. </p>
<h2 id="heading-what-is-piping-in-linux">What is Piping in Linux?</h2>
<p>Before we dive into the how, what does piping even mean? Piping is the act of directing the output of one Linux command as an input to another command. You can direct the standard output or standard error from one command to another using piping.</p>
<p>A simple example of piping is when you take the output of one command and use it as an input to another command. The pipe (|) metacharacter is used to achieve this.</p>
<p>If you're new to the concept of metacharacters, this is just a fancy name for characters with special meaning in the command line. There are other metacharacters in Linux aside from pipe (|). Common examples include less than (&lt;), greater than (&gt;), and ampersand (&amp;), to name a few.</p>
<h3 id="heading-the-basics-of-piping">The Basics of Piping</h3>
<p>The basic syntax of using the <code>pipe</code> command is as follows:</p>
<pre><code>command1 | command2 | command3 | ... | commandN
</code></pre><p>In the syntax above, the terminal will execute the commands from left to right. It will start with <code>command1</code>, and then the output will be input to <code>command2</code>. Outputs of <code>command2</code> will then be used as inputs of <code>command3</code> and so on. The good thing about piping is that you can chain as many commands as you'd like.</p>
<h3 id="heading-piping-examples">Piping Examples</h3>
<p>Below are several examples of using the <code>pipe</code> command to perform various tasks.</p>
<h4 id="heading-1-counting-the-number-of-files-and-directories">1. Counting the number of files and directories</h4>
<pre><code class="lang-bash">ls -l | wc -l
</code></pre>
<p>In the example above, the first section lists all the files and directories in the current directory using the <code>ls</code> command. The additional <code>-l</code> option tells the <code>ls</code> command to list the contents in a long list format. </p>
<p>The output of the <code>ls -l</code> command is then piped to the second section. The <code>wc -l</code> command counts the number of lines from the output of the <code>ls -l</code> command in the first section and prints the result to the terminal.</p>
<h4 id="heading-2-sorting-a-list-of-files-and-directories">2. Sorting a list of files and directories</h4>
<pre><code class="lang-bash">ls | sort
</code></pre>
<p>In the command above, the <code>ls</code> command will output the lists of the files and directories in the current directory. The list is then piped to the <code>sort</code> command, which sorts them alphabetically and prints the result to the terminal.</p>
<h4 id="heading-3-sort-and-display-unique-words-from-a-file">3. Sort and display unique words from a file</h4>
<pre><code class="lang-bash">cat words.txt | sort -r | uniq
</code></pre>
<p>The third example includes three separate commands connected by two pipes. The first command outputs the contents of the <code>words.txt</code> file, which contains a list of words. </p>
<p>The output is piped to the <code>sort -r</code> command, which sorts the words in reverse alphabetical order. Finally, the sorted words are piped to the <code>uniq</code> command, which removes duplicates and outputs the unique sorted words.</p>
<h3 id="heading-why-and-when-should-you-apply-command-piping-linux">Why and When Should You Apply Command Piping Linux?</h3>
<p>Piping takes more than just knowing the syntax. The syntax is pretty simple. To effectively use piping, you should understand its essence. </p>
<p>The purpose of piping is to help you chain commands, using the output of one as the input of another.</p>
<p>Piping is not meant to be a way to chain unrelated commands that you want to be executed sequentially. If you need to do that, write your commands in the terminal and separate them with semicolon (;) using the following syntax:</p>
<pre><code>command1 ; command2 ; ... ; commandN
</code></pre><h2 id="heading-what-is-redirection-in-linux">What Is Redirection in Linux?</h2>
<p>Redirection is the act of dictating where the inputs or outputs of your commands go. By default, commands receive data from standard input and then output the results in standard output.</p>
<p>One of the main areas where redirection proves useful is when working with commands and files. You can, for example, redirect the output of a command to a file instead of printing the output in the terminal. Alternatively, you can declare a certain file as an input to a command.</p>
<p>Like piping, Linux provides special characters to perform redirection. Here are important file-redirection characters in Linux and what they do:</p>
<ul>
<li><code>&gt;</code> – directs the output of a command to a given file.</li>
<li><code>&lt;</code> – directs the contents of a given file to a command.</li>
<li><code>&gt;&gt;</code> – directs the output of a command to a given file. Appends the output if the file exists and has content.</li>
<li><code>2&gt;</code> – directs error messages from a command to a given file.</li>
<li><code>2&gt;&gt;</code> – directs an error message from a command to a given file. Appends the error message if the file exists and has content.</li>
<li><code>&amp;&gt;</code> – directs standard output and error to a given file.</li>
<li><code>&amp;&gt;&gt;</code> – directs standard output and error to a given file. Appends to the file if it exists and has contents.</li>
</ul>
<p>Let's look at each file-redirection character in-depth.</p>
<h3 id="heading-1-output-redirection-with-gt">1. Output Redirection With <code>&gt;</code></h3>
<p>The <code>&gt;</code> symbol enables you to redirect the output of a command to a certain file. Using the symbol, you can redirect the output to any existing file. If it doesn't exist, the output redirection character will automatically create a new one. </p>
<p>However, you should be careful when writing to an existing file because its contents will be overwritten without a warning.</p>
<p>You can perform output redirection using the following syntax:</p>
<pre><code>command &gt; file
</code></pre><p>The output of running <code>command</code> will be written to the <code>file</code> instead of the standard output (or, in other words, printed to the terminal). Here's an example of how you can do output redirection:</p>
<pre><code class="lang-bash">ls -a &gt; contents.txt
</code></pre>
<p>In the command above, the list of items in the current directory (including dotfiles, directories, and files) will be written to the <code>contents.txt</code> file. You won't see any output in the terminal due to the redirection.</p>
<h3 id="heading-2-output-redirection-with-gtgt">2. Output Redirection With <code>&gt;&gt;</code></h3>
<p><code>&gt;&gt;</code> lets you redirect the output of a command to a file. But, unlike using a single greater than character (<code>&gt;</code>), <code>&gt;&gt;</code> will append the output if you try to write to an existing file (instead of overwriting its contents). If the file doesn't exist, it will create a new one.</p>
<p>The syntax is as follows:</p>
<pre><code>command &gt;&gt; file
</code></pre><p>Here's an example of using output redirection with <code>&gt;&gt;</code> to perform the same action as before:</p>
<pre><code class="lang-bash">ls -a &gt;&gt; contents.txt
</code></pre>
<h3 id="heading-3-input-redirection-with-lt">3. Input Redirection With <code>&lt;</code></h3>
<p>The <code>&lt;</code> character in the command line lets you redirect the input to a command from a file instead of the keyboard. The syntax of input redirection using <code>&lt;</code> is as follows:</p>
<pre><code>command &lt; file
</code></pre><p>Here's an example of using input redirection:</p>
<pre><code class="lang-bash">wc -w &lt; files.txt
</code></pre>
<p>In the example above, we're passing <code>files.txt</code> as the input to the <code>wc -w</code> command, which counts the number of words in the file. But you don't need to use the input redirection character in many scenarios because it's the default behavior. For instance, the command above is similar to the following:</p>
<pre><code class="lang-bash">wc -w files.txt
</code></pre>
<h3 id="heading-4-error-redirection-with-2gt-and-2gtgt">4. Error Redirection With <code>2&gt;</code> and <code>2&gt;&gt;</code></h3>
<p>When working on the command line, you may run into errors. For instance, if you want to execute a file without appropriate permissions. Instead of letting the terminal throw an error by printing it, you can use the error redirection character to dictate where the error message should go.</p>
<p>A good place to redirect errors is a file dedicated to storing errors. Here's a simple example of a command trying to access the list of files in a directory that doesn't exist:</p>
<pre><code class="lang-bash">ls nonexistent 2&gt; error.txt
</code></pre>
<p>In the example above, the terminal will throw an error since there's no file named <code>nonexistent</code>. But instead of printing it to the console, it will be stored in the <code>error.txt</code> file due to the error redirection character. However, the file will have nothing if there's no error.</p>
<p>If you must append an error to an existing file instead of overwriting its contents, use <code>2&gt;&gt;</code> instead of <code>2&gt;</code>.</p>
<h3 id="heading-5-output-and-error-redirection-with-ampgt-and-ampgtgt">5. Output and Error Redirection With <code>&amp;&gt;</code> and <code>&amp;&gt;&gt;</code></h3>
<p>Instead of choosing whether to redirect standard output or standard errors to a file, <code>&amp;&gt;</code> allows you to redirect both simultaneously. You can think of <code>&amp;&gt;</code> as a shorthand for combining the output redirection (&gt;) and error redirection (2&gt;) characters.</p>
<p>The syntax of using <code>&amp;&gt;</code> is as follows:</p>
<pre><code>command &amp;&gt; output.txt
</code></pre><p>The error or output of the <code>command</code> is written to the <code>output.txt</code> file. Here's an example:</p>
<pre><code class="lang-bash">ls sample &amp;&gt; output.txt
</code></pre>
<p>In the command above, if the <code>sample</code> directory is not available or is available but you don't have read permissions, an appropriate error will be written in the <code>output.txt</code> file. But if it exists and you have read permissions, its contents will be output in the <code>output.txt</code> file.</p>
<p>Using <code>&amp;&gt;&gt;</code> allows you to append the output to the file if it exists and has contents.</p>
<h2 id="heading-how-to-combine-piping-and-redirection-to-unleash-the-power-of-the-command-line">How to Combine Piping and Redirection to Unleash the Power of the Command Line</h2>
<p>Using piping and redirection in combination can let you perform complex operations without heavy lifting. By learning how to combine the two, you can create complex commands to perform various actions with less typing. </p>
<p>Take the following command as an example:</p>
<pre><code class="lang-bash">ls | grep <span class="hljs-string">".txt"</span> &gt; text_files.txt
</code></pre>
<p>The <code>ls</code> command lists the contents of the current directory. The output is piped to the <code>grep</code> command to filter text files. Finally, the output of the <code>grep</code> command is redirected to the <code>text_files.txt</code> file. </p>
<p>This simple yet powerful example shows that when it comes to piping and redirection, the only limit is your mind.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned the basics of piping and redirection in Linux. We covered the basics together with examples of how you can use the two. </p>
<p>The two features in isolation can be powerful, but you can go further by combining them in your commands, as shown in the last section.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Command Line Tricks You Can Learn Faster than Drinking Your Morning Coffee ]]>
                </title>
                <description>
                    <![CDATA[ In this short tutorial, I want to share with you a few tricks and tips to help you deal with some common situations when you're working in the Linux command line. We will cover the following: find xargs and nproc taskset numactl watch inotify-t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/command-line-tricks-you-can-learn-quickly/</link>
                <guid isPermaLink="false">66d85133f6b5e038a1bde804</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jose Vicente Nunez ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jan 2024 23:15:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/mazinger-z.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this short tutorial, I want to share with you a few tricks and tips to help you deal with some common situations when you're working in the Linux command line.</p>
<p>We will cover the following:</p>
<ul>
<li><p>find</p>
</li>
<li><p>xargs and nproc</p>
</li>
<li><p>taskset</p>
</li>
<li><p>numactl</p>
</li>
<li><p>watch</p>
</li>
<li><p>inotify-tools</p>
</li>
</ul>
<p>I will present you with a challenge and the tools demonstrating how to solve each problem.</p>
<h2 id="heading-what-youll-need">What You'll Need:</h2>
<ul>
<li><p>A Linux distribution</p>
</li>
<li><p>Curiosity</p>
</li>
</ul>
<h2 id="heading-how-to-handle-directories-with-many-files">How to Handle Directories with Many Files</h2>
<p>You may have encountered this problem before: you tried to do a <code>ls</code> on a directory with a very large number of files, but the command threw an 'argument list too long' error:</p>
<pre><code class="lang-shell">josevnz@orangepi5:/data/test_xargs$ ls *
-bash: /usr/bin/ls: Argument list too long
</code></pre>
<p>This is because <a target="_blank" href="https://en.wikipedia.org/wiki/POSIX">POSIX</a>-compatible systems have a limit for the maximum number of bytes you can pass as an argument:</p>
<pre><code class="lang-shell">[josevnz@dmaf5 Documents]$ getconf ARG_MAX
2097152
</code></pre>
<p>2 Million bytes may seem like a lot – or not enough depending on whom you ask. But it's also a protection against attacks or innocent mistakes with bad consequences.</p>
<p>In any case, how can you bypass this limitation? Well, there are many ways to do so.</p>
<h3 id="heading-using-shell-built-in">Using Shell built-in</h3>
<p>Bash built-in doesn't have the ARG_MAX limitation:</p>
<pre><code class="lang-shell">josevnz@orangepi5:/data/test_xargs$ echo *|ls
...
test_file055554  test_file111110  test_file166666  test_file222222  test_file277778  test_file333334  test_file388890  test_file444446
test_file055555  test_file111111  test_file166667  test_file222223  test_file277779  test_file333335  test_file388891  test_file444447
test_file055556  test_file111112  test_file166668  test_file222224  test_file277780  test_file333336  test_file388892  test_file444448
</code></pre>
<p>This is probably the simplest solution, but let's see another way.</p>
<h3 id="heading-using-find-when-you-want-formatting-options">Using <code>find</code> when you want formatting options</h3>
<p>Or you can use this well known <code>find</code> flag:</p>
<pre><code class="lang-shell">find /data/test_xargs -type f -ls -printf '%name'
</code></pre>
<p>Or with <em>formatting</em>, to mimic <code>ls</code>:</p>
<pre><code class="lang-shell">find /data/test_xargs -type f -printf '%f\n
</code></pre>
<p>This is fast and also the most complete solution. But before moving on I'll show you yet another way.</p>
<h3 id="heading-using-xargs">Using xargs</h3>
<p>The following works:</p>
<pre><code class="lang-shell">find /data/test_xargs -type f -print0 | xargs -0 ls
</code></pre>
<p>But it's inefficient, as you are forking 3 processes to display the contents of the directory. And on top of that, xargs <em>is throttling</em> how many files will be passed to the ls command.</p>
<p>Let's move on and check out a different problem.</p>
<h2 id="heading-how-to-run-more-programs-without-crashing-the-server">How to Run More Programs Without Crashing the Server</h2>
<h3 id="heading-first-you-walk-then-you-run-do-it-serially">First you walk then you run: Do it serially</h3>
<p>So say that you want to compress all the files on the given directory from our previous example. A first try would be like this:</p>
<pre><code class="lang-shell">gzip *
</code></pre>
<p>Which will take a long time as gzip will process one file at the time.</p>
<p>You might think to do something like this to compress files in parallel:</p>
<pre><code class="lang-shell">josevnz@orangepi5:/data/test_xargs$ for file in $(ls data/test_xargs/*); do gzip $file &amp;; done
-bash: /usr/bin/ls: Argument list too long
</code></pre>
<p>Again, ARG_MAX strikes again.</p>
<p>We know xargs or find now, so what if we do this:</p>
<pre><code class="lang-shell">for file in $(find $PWD); do echo gzip $file &amp;; done
wait
echo "All files compressed?"
</code></pre>
<p>That will either make your <strong>server run out of memory</strong> or <strong>crush it under very heavy CPU utilization</strong> because you are forking a gzip instance for every file found.</p>
<h3 id="heading-our-first-attempt-at-parallelism-and-throttling-the-art-of-self-control">Our first attempt at parallelism and throttling (the art of self control)</h3>
<p>What you need is a way to <em>throttle</em> your compression requests, so you don't launch more processes than the number of CPUS you have.</p>
<p>Let's try that again with <code>find</code> and <code>xargs</code>:</p>
<pre><code class="lang-shell">find /data/test_xargs -type f -print0| xargs -0 -P $(($(nproc)-1)) -I % gzip %
</code></pre>
<p>Oh. That looks like a fancy one-liner. Let me explain how it works:</p>
<ol>
<li><p>Use <code>find</code> to get all files on the given directory, use the null character as a separator to be able to process weird named ones.</p>
</li>
<li><p><code>nproc</code> will tell you how many CPUS you have, then subtract 1 using Bash arithmetic like this using sub-shells: <code>$(($(nproc)-1))</code></p>
</li>
<li><p>Finally, <code>xargs</code> will run no more than -P processes (In my case 8 CPUS - 1 = 7 jobs), replacing the '%' with the name of the file to compress</p>
</li>
</ol>
<p>Note: There are other ways to get the number of CPUS on the machine, like parsing <code>/proc/cpuinfo</code>. There are other more efficient compression out there but gzip is available on pretty much any Linux/ Unix out there.</p>
<p>OK, time to see our next problem.</p>
<h2 id="heading-cpu-affinity-with-taskset-to-maximize-execution-time">CPU Affinity with taskset to Maximize Execution Time</h2>
<p>Despite limiting the number of CPUs, some intensive jobs can slow down other processes on your machine when looking for resources. There are a few things you can do to keep the performance of the server under control, like using <a target="_blank" href="https://github.com/util-linux/util-linux/blob/master/schedutils/taskset.c">taskset</a>:</p>
<blockquote>
<p>The taskset command is used to set or retrieve the CPU affinity<br>of a running process given its pid, or to launch a new command<br>with a given CPU affinity. CPU affinity is a scheduler property<br>that "bonds" a process to a given set of CPUs on the system.</p>
</blockquote>
<p>In general, we always want to leave one of the CPUS 'free' for operating system tasks. The Kernel is normally pretty good keeping running processes glued to a specific CPU to avoid context switching, but if you want to enforce on which CPUS your process will run you can use <code>tasket</code></p>
<pre><code class="lang-shell">taskset -c 1,2,3,4,5,6,7 find /data/test_xargs -type f -print0| xargs -0 -P $(($(nproc)-1)) -I % gzip %
</code></pre>
<h3 id="heading-taskset-the-only-game-in-town-not-so-numactl-fast">taskset the only game in town? not so numactl fast!</h3>
<p>What is <a target="_blank" href="https://documentation.suse.com/sles/12-SP4/html/SLES-all/cha-tuning-numactl.html">NUMA and why you should care</a>?</p>
<blockquote>
<p>There are physical limitations to hardware that are encountered when many CPUs and lots of memory are required. The important limitation is that there is limited communication bandwidth between the CPUs and the memory.</p>
<p>One architecture modification that was introduced to address this is Non-Uniform Memory Access (NUMA).</p>
</blockquote>
<p>So most simple desktop machines only have a single NUMA node, like mine:</p>
<pre><code class="lang-shell">[josevnz@dmaf5 ~]$ numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 15679 MB
node 0 free: 5083 MB
node distances:
node   0 
  0:  10
# Or with lscpu
[josevnz@dmaf5 ~]$ lscpu |rg NUMA
NUMA node(s):                    1
NUMA node0 CPU(s):               0-7
</code></pre>
<p>If you have more than one NUMA node, you may want to 'pin' or set the affinity of your program to use the CPUS and memory of the same node.</p>
<p>For example, on a machine with 16 cores, 0-7 on node 0, 8-15 on node 1, we could force our compression program to run on all the CPUS on node 1, and use the memory of node 1 like this:</p>
<pre><code class="lang-shell">numactl --physcpubind 8-15 --membind=1 find /data/test_xargs -type f -print0| xargs -0 -P $(($(nproc)-1)) -I % gzip %
</code></pre>
<h2 id="heading-keeping-an-eye-on-things">Keeping an Eye on Things</h2>
<h3 id="heading-just-watch-what-i-do">Just watch what I do</h3>
<p>The <a target="_blank" href="https://www.man7.org/linux/man-pages/man1/watch.1.html">watch</a> command allows you to periodically run a command, and even show you the differences before calls:</p>
<pre><code class="lang-shell">Every 10.0s: ls                                                                                                         orangepi5: Wed May 24 22:46:33 2023

test_file000001.gz
test_file000002.gz
test_file000003.gz
test_file000004.gz
test_file000005.gz
test_file000006.gz
test_file000007.gz
test_file000008.gz
test_file000009.gz
test_file000010.gz
...
</code></pre>
<p>Shows me the output of the <code>ls</code> command every 10 seconds. To detect changes on a directory this is simple, but not easy to automate and definitely not efficient.</p>
<p>Wouldn't be nice if the kernel was able to tall me about changes on my directories?</p>
<h3 id="heading-a-better-way-to-know-about-changes-on-the-filesystem-with-inotify-tools">A better way to know about changes on the filesystem, with inotify-tools</h3>
<p>You may need to install this separately, but it should be easy to do. On Ubuntu:</p>
<pre><code class="lang-shell">sudo apt-get install inotify-tools
</code></pre>
<p>On Fedora:</p>
<pre><code class="lang-shell">sudo dnf install -y inotify-tools
</code></pre>
<p>So how we can monitor for events on a given directory?</p>
<p>On one terminal we can run inotifywait:</p>
<pre><code class="lang-shell">josevnz@orangepi5:/data/test_xargs$ inotifywait --recursive /data/test_xargs/
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
</code></pre>
<p>And on another terminal we can touch some files to simulate an event:</p>
<pre><code class="lang-shell">josevnz@orangepi5:/data/test_xargs$ pwd
/data/test_xargs
josevnz@orangepi5:/data/test_xargs$ touch test_file285707.gz test_file357136.gz test_file428565.gz
</code></pre>
<p>The original terminal will get the first event and exit:</p>
<pre><code class="lang-shell">Watches established.
/data/test_xargs/ OPEN test_file285707.gz
</code></pre>
<p>To make it listen for even forever we do this:</p>
<pre><code class="lang-shell">josevnz@orangepi5:/data/test_xargs$ inotifywait --recursive --monitor /data/test_xargs/
</code></pre>
<p>If we touch the file again on a separate terminal then this time we will see all the events:</p>
<pre><code class="lang-shell">Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
/data/test_xargs/ OPEN test_file285707.gz
/data/test_xargs/ ATTRIB test_file285707.gz
/data/test_xargs/ CLOSE_WRITE,CLOSE test_file285707.gz
/data/test_xargs/ OPEN test_file357136.gz
/data/test_xargs/ ATTRIB test_file357136.gz
/data/test_xargs/ CLOSE_WRITE,CLOSE test_file357136.gz
/data/test_xargs/ OPEN test_file428565.gz
/data/test_xargs/ ATTRIB test_file428565.gz
/data/test_xargs/ CLOSE_WRITE,CLOSE test_file428565.gz
</code></pre>
<p>This is less taxing to the operating system than asking for directory changes every time, and filtering just the differences ourselves.</p>
<h2 id="heading-whats-next">What's Next</h2>
<p>There is so much more to explore. The tips above introduced you to some important concepts, so why not to learn much more about them?</p>
<ul>
<li><p>The <a target="_blank" href="https://askubuntu.com/questions/217764/argument-list-too-long-when-copying-files">Ubuntu forum</a> has a great conversation about <em>xargs</em>, <em>find</em>, <em>ulimit</em> and other things. Knowledge is power.</p>
</li>
<li><p>RedHat as <a target="_blank" href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/monitoring_and_managing_system_status_and_performance/configuring-an-operating-system-to-optimize-cpu-utilization_monitoring-and-managing-system-status-and-performance">a nice page</a> about NUMA, taskset, interrupt handling. If you are serious about fine-tuning the performance of your processes, please read it.</p>
</li>
<li><p>You liked <a target="_blank" href="https://en.wikipedia.org/wiki/Inotify">inotify</a> and want to use it from your Python script. Then take a look at <a target="_blank" href="https://github.com/seb-m/pyinotify/wiki">pynotify</a>.</p>
</li>
<li><p>Find may be intimidating, but <a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-use-find-and-locate-to-search-for-files-on-linux">this tutorial</a> will make it easier to understand.</p>
</li>
<li><p>Source code for this tutorial can be found <a target="_blank" href="https://github.com/josevnz/CommandLineTipsAndTricks">here</a>.</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the WordPress Command Line Interface – WP-CLI Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ In the world of website development and content management, efficiency and automation are key. The WordPress Command Line Interface – or WP-CLI – is a powerful tool that can help you streamlines tasks and manage WordPress websites more effectively.  ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-wordpress-cli/</link>
                <guid isPermaLink="false">66bdff6a0b4523e3b8b99099</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Marco Venturi ]]>
                </dc:creator>
                <pubDate>Fri, 11 Aug 2023 21:37:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/pexels-pixabay-207580.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the world of website development and content management, efficiency and automation are key. The WordPress Command Line Interface – or WP-CLI – is a powerful tool that can help you streamlines tasks and manage WordPress websites more effectively. </p>
<p>This article provides an overview of WP-CLI, focusing on its capabilities to create, modify, and delete users, as well as handle plugins with ease. This article will show you how WP-CLI can significantly elevate your WordPress management experience.</p>
<h2 id="heading-what-is-wp-cli">What is WP-CLI?</h2>
<p>WP-CLI is a command-line tool designed for managing WordPress installations. It empowers developers, administrators, and site owners to interact with their websites directly from the command line, bypassing the need for manual interventions through the web interface. </p>
<p>It's built on PHP, and offers a wide range of commands that you can execute right from the terminal.</p>
<p>By using WP-CLI, you'll be able to manage your WordPress sites much more efficiently. Let's see a few examples of how WP-CLI commands can simplify your workflow:</p>
<h2 id="heading-wp-cli-commands">WP-CLI Commands</h2>
<h3 id="heading-site-information-retrieval">Site Information Retrieval</h3>
<p>The <code>wp site info</code> command provides a quick overview of your WordPress site's important details, including the site's URL, the number of posts and pages, the active theme, and more. </p>
<p>For instance, by running <code>wp site info</code>, you can promptly gather essential information about your site without navigating through the WordPress admin dashboard.</p>
<h3 id="heading-database-management">Database Management</h3>
<p>WP-CLI allows you to manage your WordPress database seamlessly. Use the <code>wp db export</code> command to create a database export file, ensuring a backup of your site's data. </p>
<p>If you need to import data, the <code>wp db import</code> command facilitates this process. For example, if you have a database backup named <code>backup.sql</code>, executing <code>wp db import backup.sql</code> restores the database to a previous state.</p>
<h3 id="heading-theme-manipulation">Theme Manipulation</h3>
<p>Manipulating themes is extremely efficient with WP-CLI. For example, the <code>wp theme install</code> command lets you install a theme directly from the official WordPress theme repository. To install the "Twenty Twenty-One" theme, you can use the command <code>wp theme install twentytwentyone</code>.</p>
<h3 id="heading-post-and-page-creation">Post and Page Creation</h3>
<p>Generating new content is made easier using WP-CLI. The <code>wp post create</code> and <code>wp post generate</code> commands enable you to create and populate posts and pages with content. </p>
<p>For example, <code>wp post create --post_type=post --post_title="New Post"</code> creates a new post with the specified title.</p>
<p>These examples illustrate the versatility and power of WP-CLI in managing various aspects of your WordPress site. By harnessing its capabilities, you can enhance your efficiency, reduce manual tasks, and gain greater control over your website's management.</p>
<h2 id="heading-how-to-install-wp-cli">How to Install WP-CLI</h2>
<p>Before diving into more features of WP-CLI, let's understand the installation process. </p>
<p>You can install WP-CLI globally on your system, making it accessible from any directory. </p>
<p>To install WP-CLI, make sure you have PHP installed, along with a compatible version of WordPress. Download the Phar archive, place it in a directory reachable through your system's PATH, and you're ready to go. </p>
<p>You can verify the installation by typing <code>wp --info</code> in your terminal. <a target="_blank" href="https://wp-cli.org">Here</a> you can find the doc with the URL to download WP-CLI with a wget.</p>
<h2 id="heading-how-to-manage-users-with-wp-cli">How to Manage Users with WP-CLI</h2>
<p>Managing users is a fundamental task when overseeing a WordPress site. WP-CLI simplifies user management with various commands that make creating, modifying, and deleting users much easier.</p>
<h3 id="heading-how-to-create-users">How to Create Users</h3>
<p>The <code>wp user create</code> command lets you quickly create users directly from the command line. </p>
<p>To illustrate, let's create a new user named "Alice" with the email address "alice@example.com" and the role of editor. Simply enter:</p>
<pre><code>wp user create alice alice@example.com --role=editor
</code></pre><h3 id="heading-how-to-modify-users">How to Modify Users</h3>
<p>WP-CLI also streamlines user modifications. Use the <code>wp user update</code> command to adjust a user's details. </p>
<p>For instance, let's change Alice's display name to "Alice Johnson" using the following command:</p>
<pre><code>wp user update <span class="hljs-number">123</span> --display_name=<span class="hljs-string">"Alice Johnson"</span>
</code></pre><p>In this example, "123" is Alice's ID.</p>
<h3 id="heading-how-to-delete-users">How to Delete Users</h3>
<p>When user accounts become obsolete or require removal for security reasons, WP-CLI simplifies the process. </p>
<p>To delete a user, use the <code>wp user delete</code> command. To remove Alice's account, simply execute:</p>
<pre><code>wp user <span class="hljs-keyword">delete</span> <span class="hljs-number">123</span> --reassign=<span class="hljs-number">567</span>
</code></pre><p>In this case, again "123" is Alice's ID and "567" is the ID of the user you want to assign Alice's content to (for example posts, pages, and so on).</p>
<h2 id="heading-how-to-manage-plugins-with-wp-cli">How to Manage Plugins with WP-CLI</h2>
<p>Plugins play a crucial role in enhancing WordPress websites. WP-CLI extends its capabilities to manage plugins, making tasks such as installation, activation, deactivation, and updates incredibly efficient.</p>
<h3 id="heading-how-to-install-plugins">How to Install Plugins</h3>
<p>Use the <code>wp plugin install</code> command to seamlessly install plugins from the WordPress repository. </p>
<p>For instance, let's install the "Akismet" anti-spam plugin:</p>
<pre><code>wp plugin install akismet
</code></pre><h3 id="heading-how-to-activate-and-deactivate-plugins">How to Activate and Deactivate Plugins</h3>
<p>Managing plugin status is quite easy with WP-CLI. Activate or deactivate plugins using the <code>wp plugin activate</code> and <code>wp plugin deactivate</code> commands respectively. </p>
<p>To activate the "Akismet" plugin, type the following command:</p>
<pre><code>wp plugin activate akismet
</code></pre><h3 id="heading-how-to-update-plugins">How to Update Plugins</h3>
<p>Keeping plugins up to date is vital for security and performance. The <code>wp plugin update</code> command makes updates hassle-free. </p>
<p>To update all installed plugins, simply run:</p>
<pre><code>wp plugin update --all
</code></pre><h3 id="heading-how-to-list-installed-plugins">How to List Installed Plugins</h3>
<p>WP-CLI offers an overview of installed plugins with the <code>wp plugin list</code> command. This provides a quick snapshot of each plugin's status, version, and available updates:</p>
<pre><code>wp plugin list
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>WP-CLI is an invaluable asset in the world of WordPress management. Its extensive command set helps you manage users and plugins – and much more – with remarkable ease. This saves you time and minimizes manual interventions. </p>
<p>By harnessing the power of WP-CLI, administrators and developers can streamline workflows, improve security, and ensure their WordPress websites operate seamlessly. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CLI Shells – A Brief History of Human-Computer Interfaces ]]>
                </title>
                <description>
                    <![CDATA[ By Chidiadi Anyanwu A computer is basically a piece of electronic circuitry that performs tasks as instructed by its users. But for a human to interact with this hardware, they must really know and understand how it works. The person must also know t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/shells-a-history-of-human-computer-interfaces/</link>
                <guid isPermaLink="false">66d45dd7868774922c884fcd</guid>
                
                    <category>
                        <![CDATA[ cli ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Computer Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ shell ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chidiadi Anyanwu ]]>
                </dc:creator>
                <pubDate>Tue, 18 Jul 2023 16:45:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/Evernote-cli-geeknote.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Chidiadi Anyanwu</p>
<p>A computer is basically a piece of electronic circuitry that performs tasks as instructed by its users.</p>
<p>But for a human to interact with this hardware, they must really know and understand how it works. The person must also know the order in which to give the computer various tasks to produce a meaningful result.</p>
<p>But most of us don't know these things. What happened?</p>
<p>In this article, we're going to look at:</p>
<ul>
<li><p>The history of early computing</p>
</li>
<li><p>How operating systems were developed</p>
</li>
<li><p>Modern operating systems</p>
</li>
<li><p>The development of kernels and shells</p>
</li>
<li><p>The history of shells</p>
</li>
<li><p>Why CLI tools are still important</p>
</li>
</ul>
<h2 id="heading-the-early-days-of-computers">The Early Days of Computers</h2>
<p>In the 1800's, computers were mostly used to work on large amounts of numerical data. They were basically programmable calculators the size of small factories.</p>
<p>The data they worked on were also very physical. They were manually fed as punched cards into the machine's card readers. The computers were then programmed by physically rewiring cables, plugboards, and switches to determine what operations would be carried out on the input data. Some of the computers even processed logic through partially mechanical means.</p>
<p>Plugboards allowed you write (or wire) a program and store it so when you needed that program, you'd remove the current plugboard and install a new one. The output of the programs were printed out by line printers, saved on tapes, or punched on cards.</p>
<p>These programming and memory technologies were used in many forms of technological designs.</p>
<p>For example, the Enigma machine which was used to scramble letters and encipher top secret military and diplomatic communication had a plugboard you would rewire to change settings.</p>
<p>The IBM International Daily Dial Attendance Recorder also counted and recorded staff attendance on punched cards. These were more special-purpose equipment.</p>
<h2 id="heading-early-operating-systems">Early Operating Systems</h2>
<p>The first-ever speech synthesis was done in 1962 on an IBM 704, a computer without an operating system.</p>
<p>At the time of the first computers, nobody ever thought of operating systems. People wrote their programs in machine language (or wired them on plugboards) and ran them. There was no way to run two programs at the same time or perform error detection/correction. Your program ran until it either crashed or completed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/IBM_Electronic_Data_Processing_Machine_-_GPN-2000-001881-IBM-704.jpg" alt="Picture of a man and a woman operating the IBM 704 in 1957." width="600" height="400" loading="lazy"></p>
<p><em>IBM 704 computer with two operators in 1957</em></p>
<p>Initially, computers didn't ship with any software. Later on, IBM included FORTRAN and COBOL compilers in their mainframes. Then came 'resident monitors,' the precursor to operating systems. They literally got the name because they were software that resided in the company's memory and monitored tasks. They basically performed tasks like cleaning up after programs and helping to sequence jobs on the computers.</p>
<p>The first operating systems were made by computer owners who were tired of under-utilizing their computers. They didn't want to have to wait for a program to complete before they manually loaded in another set of data and programs.</p>
<p>One of these early operating systems was the Input/Output System of General Motors and North American Aviation (GM-NAA I/O). Its main aim was to execute the next program automatically after the current one was finished (batch processing). It was created in 1956, and is known as the first-ever working operating system.</p>
<p>IBM later modified one of its customer's operating systems and distributed it as IBSYS. Then, IBM thought that it wasn't good for different computers to have different (machine language) instruction sets, so they stopped all production and started a new line called System/360.</p>
<p>With this, they aimed to build just one operating system for all their computers. It didn't quite go as planned, so they ended up with a family of operating systems, OS/360.</p>
<p>OS/360 included features like time-sharing, error detection/correction, and device management, which are all features implemented in modern operating systems. The OS/360 was introduced in 1964 and was in use until 1977.</p>
<p>Early time-sharing technologies enabled multiple people to access the same mainframe from their different terminals at once. The first computer terminals were teletypewriters (or teletypes). Teletypes were developed around the 1830's but weren't used as computer terminals until the 1970's.</p>
<h2 id="heading-modern-operating-systems">Modern Operating Systems</h2>
<p>The MULTiplexed Information and Computing Service (MULTICS) operating system was initially developed for General Electric's 645 mainframe, and later Honeywell's mainframes when they bought over GE's computer division.</p>
<p>It was jointly developed in 1964 by GE, MIT, and Bell Labs, mainly as a successor to the Compatible Time-Sharing System (CTSS).</p>
<p>It came with a lot of new ideas to the computing world like access control, dynamic linking, support for ASCII, and dynamic reconfiguration.</p>
<p>Dynamic reconfiguration allowed the operators to remove and add memories and CPUs without logging out or disrupting users. With the advent of the Compatible Time-Sharing System (CTSS), computers were looked at as a utility.</p>
<p>The idea was that computers were too big and expensive and could be used by only one person at a time. But what if that expensive hardware could be used more efficiently by allowing more than one person to use them at the same time? That way, the computer could become a public utility, accessed from home with terminals.</p>
<p>With a public utility, you need to be able to carry out maintenance on different components without disrupting the service. That was the usefulness of dynamic reconfiguration.</p>
<p>That idea of computers becoming a public utility seems to have lived on with the use of servers, and now, cloud computing.</p>
<p>At a point, MULTICS didn't work out and the companies went their separate ways. Ken Thompson, one of the programmers, later described MULTICS as 'over-designed,' 'overbuilt,' and close to unusable. In an interview with Peter Seibel, he said that the things he liked enough to take from it were the hierarchical filesystem and the shell.</p>
<p>He later went on to create the UNIX operating system with Dennis Ritchie.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/Timeline-Computers.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-the-development-of-kernels-and-shells">The Development of Kernels and Shells</h2>
<p>One of the major features of the UNIX operating system was the splitting of the operating system into shell and kernel. The OS kernel was then meant to handle all the system calls, while the shell was used to access the system's services without exposing the inner workings of the operating system.</p>
<p>This concept was first introduced by French computer scientist Louis Pouzin in 1965. He also coined the term shell. This is how he described it in a document titled, <a target="_blank" href="https://people.csail.mit.edu/saltzer/Multics/Multics-Documents/MDN/MDN-4.pdf">The SHELL: A Global Tool for Calling and Chaining Procedures in the System</a>.</p>
<blockquote>
<p>We may envision a common procedure called automatically by the supervisor whenever a user types in some message at his console . . . we shall refer to that procedure as the "SHELL".</p>
</blockquote>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/Louis-Pouzin-Shell-Document-Definition.png" alt="Louis Pouzin Shell Document Definitionpng" width="600" height="400" loading="lazy"></p>
<p><em>Louis Pouzin's Document on Shells</em></p>
<p>According to the document, when the user types in a command, the supervisor initiates a new stack to save the command, then calls the shell with the command as an argument.</p>
<p>He also envisioned a future where people created their own shells and used them without having to meddle with the underlying structure of the shell.</p>
<blockquote>
<p>"An important facility is that the SHELL being itself a common procedure may be replaced by a private one supplied by the user. On that way, not only a particular procedure can be replaced on user's choice, but all conventions about typing commands may be tailor-made to user's wishes just by providing his own SHELL."</p>
</blockquote>
<p>This idea was first implemented in MULTICS, and is one of the only things Ken Thompson admitted to liking enough to take from the project.</p>
<p>Now, in modern operating systems, the shell is the software that lets you communicate with the operating system, and access the OS services which are things like program execution, file management, and I/O management. It could be a command-line shell (CLI) or it could be a graphical user interface (GUI).</p>
<p>The kernel is the part that handles all the system calls, manages computer resources like memory, CPU, and storage, and handles timesharing between processes.</p>
<h2 id="heading-history-of-cli-shells">History of CLI Shells</h2>
<p>Shells as we know them now really began with UNIX, and one of the first was the Thompson shell.</p>
<h3 id="heading-thompson-shell-1971">Thompson Shell (1971)</h3>
<p>Ken Thompson, of course, went on to create his own shell. It was a simple command interpreter, not designed for scripting. It introduced the &lt; &gt; symbols for redirecting the input or output of a command, and the | symbol for piping.</p>
<h3 id="heading-c-shell-1978">C Shell (1978)</h3>
<p>The C Shell (or csh) was created by Bill Joy and enabled scripting. The objective was to create a command language that looked more like the C programming language.</p>
<h3 id="heading-bourne-shell-1979">Bourne Shell (1979)</h3>
<p>Stephen Bourne started work on the Bourne Shell in 1976 as a replacement for the Thompson Shell. It was intended as a scripting language. One of the major goals was to enable using scripts as filters.</p>
<h3 id="heading-korn-shell-1983">Korn Shell (1983)</h3>
<p>Developed by David Korn, the Korn Shell was based on source code from the Bourne Shell, and attempted to integrate the features of C Shell and Bourne Shell. It is <a target="_blank" href="https://en.wikipedia.org/wiki/POSIX">POSIX.2</a> compliant.</p>
<h3 id="heading-bourne-again-shell-aka-bash-1989">Bourne Again SHell aka BASH (1989)</h3>
<p>BASH was written by Brian Fox in 1989 and released under the GNU license as a free and open-source version of the Bourne Shell.</p>
<p>It was one of the first programs Linus Torvalds ported to Linux and is the default shell for most Linux distributions. It was built for scripting and is <a target="_blank" href="https://en.wikipedia.org/wiki/POSIX">POSIX</a> compliant.</p>
<h3 id="heading-z-shell-1990">Z Shell (1990)</h3>
<p>The Z Shell (or Zsh) was created by Paul Falstad as an extended and improved Bourne Shell. The name was derived from the name of a teaching assistant at Paul's university named Zhong Shao.</p>
<p>It also enables scripting and is aesthetically superior to Bash. It supports plugins and extensions, auto-completion, and some other globing capabilities that are unavailable in Bash.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/Timeline-Shells-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>There are many other popular shells used today, but I'm not going to talk about them.</p>
<p>All these shells mentioned did not apply to Windows (until recently). Windows had two command-line shells: Command Prompt (cmd) and PowerShell. The PowerShell was created as an extension to Command Prompt. It supports cmdlets, scripting, piping, and many more features.</p>
<p>Then in 2019, that changed with Windows Terminal, a new terminal emulator for Windows that can run Bash on what is called Windows Subsystem for Linux (WSL). It also supports Command Prompt, PowerShell, and Azure Cloud shell out-of-the-box.</p>
<h2 id="heading-why-are-these-cli-tools-important-when-we-have-graphical-user-interfaces-guis">Why Are These CLI Tools Important When We Have Graphical User Interfaces (GUIs)?</h2>
<p>You may wonder why we would take the pains to go through this whole evolution and yet still love to use CLI tools and shells. What's so interesting about typing commands into terminals?</p>
<p>The first and most compelling reason is that CLI tools are lightweight because they're text-based. In cases where you have servers and other devices where you need to optimize the use of resources, it's not very wise to use up most of the resources to run GUI interfaces.</p>
<p>Using the CLI can also provide you with a great deal of flexibility and speed that you won't get with a GUI. For example, you may want to search for all the images in a folder with 1000 files and rename them in a certain order. Doing that with your GUI will be time-consuming and maybe frustrating. With the CLI, you can just type a few commands.</p>
<p>Scripts are another important feature. Sometimes, there are tasks you want to carry out multiple times and you don't want to have to navigate through menus all the time or even type commands multiple times. You can write scripts that you run to automatically carry out the tasks repetitively.</p>
<p>In cases where you have to access devices remotely, like web servers or network devices, the CLI is also the most favoured method. Also, for some tasks, it's just easier to do them with a few commands than using your GUI—updating your apps on Linux for example.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>We've really come a long way from purely mechanical computers to purely electronic computers. The way we interact with computers has changed over the decades, but command-line interfaces aren't going anywhere soon.</p>
<p>Thanks for reading. I hope you enjoyed this article. You can <a target="_blank" href="https://www.linkedin.com/in/chidiadi-anyanwu">connect with me on LinkedIn.</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Helpful Linux Commands You Should Know ]]>
                </title>
                <description>
                    <![CDATA[ Ever feel like you’ve mastered the basics of Linux and are ready to level up your skills? Well, good news – there are many powerful commands that you might not know about. In this article, I'll introduce you to some lesser-known Linux commands that w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/helpful-linux-commands-you-should-know/</link>
                <guid isPermaLink="false">66c8619c74f6ae8759515601</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rahul ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jul 2023 20:36:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/gabriel-heinzer-4Mw7nkQDByk-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Ever feel like you’ve mastered the basics of Linux and are ready to level up your skills? Well, good news – there are many powerful commands that you might not know about.</p>
<p>In this article, I'll introduce you to some lesser-known Linux commands that will help you become a more productive and effective developer.</p>
<p>Whether you’re looking to boost your productivity, tighten system security, or just want to show off your Linux chops to fellow devs, these commands have you covered.</p>
<h2 id="heading-chroot-run-commands-with-a-different-root-directory">Chroot: Run Commands With a Different Root Directory</h2>
<p>Ever wanted to run commands in a different root directory? The chroot command allows you to do just that.</p>
<p>Chroot, short for “<em>change root</em>,” lets you run commands with a different root directory. So if you wanted to test out software in a contained environment or build a minimal Linux system, chroot is your friend.</p>
<p>To use chroot, first you’ll need to set up a directory to act as the new root. Then you run the chroot command, passing it the path to that directory. For example, to chroot into <strong>/home/testdir,</strong> you’d run:</p>
<pre><code class="lang-bash">chroot /home/testdir
</code></pre>
<p>After that, any commands you run will be relative to / in the <code>/home/testdir directory</code>. So you could install packages, run shell scripts, compile programs, and so on. When you’re done, just exit the chroot with <code>exit</code>.</p>
<p>Chroot creates an isolated environment, so any changes you make won’t affect the rest of your system. It’s a handy <strong>tool for testing and development or for emergency recovery</strong>. Once you get familiar with chroot, you’ll find all sorts of uses for it.</p>
<h2 id="heading-crontab-schedule-tasks-to-run-automatically">Crontab: Schedule Tasks to Run Automatically</h2>
<p>Crontab is a handy Linux command that lets you schedule tasks to run automatically at specific times. You’ll wonder how you ever lived without it!</p>
<p>To get started, open the crontab file with <code>crontab -e</code>. This will open your default text editor where you can create schedule entries, called <a target="_blank" href="https://www.freecodecamp.org/news/cron-jobs-in-linux/">cron jobs</a>. Each entry has five-time fields – minute, hour, day of month, month, day of week, followed by the command to run.</p>
<p>For example, <code>0 0 * * * /home/user/daily_script.sh</code> would run the <strong>daily_script.sh</strong> script at midnight every day. You can also do <code>30 8 * * 1-5 /home/user/work_script.sh</code> to run <strong>work_script.sh</strong> at 8:30am every weekday.</p>
<p>Crontab allows a ton of flexibility. You can schedule jobs to run:</p>
<ul>
<li>Minutely, hourly, daily, weekly, monthly or yearly</li>
<li>At a specific minute/hour</li>
<li>On certain days of the week/month</li>
<li>With wildcards to run, for example every 3 hours or every Monday and Thursday</li>
</ul>
<p>The possibilities are endless! You can schedule backup scripts, system maintenance, email reports and so much more.</p>
<h2 id="heading-df-check-disk-space-usage">Df: Check Disk Space Usage</h2>
<p>Ever run out of disk space and wonder where it all went? The <code>df</code> command is here to help. df stands for “<em>disk free</em>” and shows you exactly how much space is used and available on your Linux system.</p>
<h3 id="heading-check-usage-for-all-mounted-filesystems">Check Usage for All Mounted Filesystems</h3>
<p>To see an overview of disk space usage for all mounted drives and partitions, simply run:</p>
<pre><code class="lang-bash">df -h
</code></pre>
<p>The <code>-h</code> flag formats the output in human-readable format, showing sizes in GB and MB instead of bytes. The output will show:</p>
<ul>
<li>Filesystem: The drive or partition name</li>
<li>Size: Total space</li>
<li>Used: Space currently in use</li>
<li>Available: Free space still available</li>
<li>Use%: Percentage of space used</li>
</ul>
<p>This gives you a quick snapshot of where you have space and where it's running low.</p>
<h3 id="heading-check-usage-for-a-specific-filesystem">Check Usage for a Specific Filesystem</h3>
<p>To check space on a specific drive or partition, pass its mount point to df:</p>
<p><code>df -h /home</code></p>
<p>This will show usage stats just for your /home partition.</p>
<p>Keeping an eye on disk usage with df and related tools is important for any Linux system administrator. No one wants to run out of space unexpectedly.</p>
<h2 id="heading-dmesg-view-kernel-messages">Dmesg: View Kernel Messages</h2>
<p>Ever wonder what’s happening behind the scenes in your Linux system? The <strong>dmesg</strong> command lets you peek under the hood and view messages from the kernel, the core of your operating system.</p>
<p>When your Linux system boots up, the kernel initializes hardware, loads drivers, starts services, and performs other startup tasks. The <strong>dmesg</strong> command displays the messages that get logged during this process so you can see what’s going on.</p>
<p>To view the kernel messages, just open your terminal and run the dmesg command. You'll see pages and pages of status <strong>updates</strong>, <strong>diagnostics</strong>, <strong>errors</strong>, and more as your system came to life. Skim through to check for any issues, or search for specific keywords like the name of your Wi-Fi adapter or other hardware components.</p>
<p>The <strong>dmesg</strong> output can also provide clues to solving any problems you're having. For example, if your network isn’t working, <strong>check dmesg for error messages related to your Ethernet or wireless card</strong>. You may spot something like “error initializing network device eth0” that points you to a driver issue.</p>
<p>The <code>dmesg</code> command is a handy diagnostic tool for any Linux system administrator or power user. It offers an inside look at your Linux system and can help uncover the source of both major malfunctions and minor annoyances. Ps: you can feel like a hacker.</p>
<h2 id="heading-grep-search-for-patterns-in-files">Grep: Search for Patterns in Files</h2>
<p>The grep command allows you to search for patterns in files and text. It’s ideal when you need to find something specific in a sea of data.</p>
<p>Say you have a massive log file full of information, but you only want to see the lines containing the word “error.” Just run:</p>
<pre><code class="lang-bash">grep error log.txt
</code></pre>
<p>This will print only the lines in log.txt that contain the word “error.”</p>
<p>You can also use grep to search for patterns rather than just words. For example, to find all lines in a file that start with “A” followed by a number, use:</p>
<pre><code class="lang-bash">grep ^A[0-9] log.txt
</code></pre>
<p>The <code>^A</code> anchors the match to the start of the line, and [0-9] matches any digit.</p>
<p>Grep has many more advanced features as well. You can use:</p>
<ul>
<li>Regex patterns for complex searches</li>
<li><code>-i</code> to ignore case</li>
<li><code>-v</code> to invert the search and show lines that <em>don’t</em> match</li>
<li><code>-c</code> to just get a count of matches</li>
<li><code>-r</code> to recursively search all files in a directory</li>
</ul>
<p>The next time you need to search through files, don’t do it manually—let grep do the work for you.</p>
<h2 id="heading-headtail-view-the-firstlast-part-of-a-file">Head/Tail: View the First/Last Part of a File</h2>
<p>Have you ever needed to quickly check just the first or last few lines of a long file? The head and tail commands are perfect for that.</p>
<p>The <code>head</code> command shows you the first 10 lines of a file by default. You can specify how many lines you want to see by using the <code>-n</code> flag, like <code>head -n 5 filename</code> to show the first 5 lines.</p>
<p>The <code>tail</code> command shows you the last 10 lines of a file by default. Again, use the <code>-n</code> flag to specify how many lines you want to see, like <code>tail -n 20 filename</code> to show the last 20 lines.</p>
<p>Both <code>head</code> and <code>tail</code> are useful when you want to do a quick check of the start or end of a long file without having to scroll through the entire thing. Some other uses of these commands:</p>
<ul>
<li>Checking log files for recent errors or warnings</li>
<li>Viewing email headers</li>
<li>Previewing configuration files</li>
<li>And more!</li>
</ul>
<p>Give <code>head</code> and <code>tail</code> a try – you'll be amazed at how much simpler they make tasks you do all the time.</p>
<h2 id="heading-ps-list-running-processes">Ps: List Running Processes</h2>
<p>The Ps command allows you to see info about the processes running on your system. This includes programs, commands, and daemons that are currently active. Using Ps is a quick way to get an overview of what your Linux system is doing at the moment and the system resources each process is using.</p>
<p>To see a basic list of running processes, enter:</p>
<pre><code class="lang-bash">ps aux
</code></pre>
<p>This will show you:</p>
<ul>
<li>A: All processes</li>
<li>U: User</li>
<li>X: Processes without terminals</li>
</ul>
<p>The output will contain info like:</p>
<ul>
<li><strong>USER</strong>: The owner of the process</li>
<li><strong>PID</strong>: The process ID</li>
<li><strong>%CPU</strong>: The CPU usage</li>
<li><strong>%MEM</strong>: The memory usage</li>
<li><strong>VSZ</strong>: The virtual memory usage</li>
<li><strong>TTY</strong>: The terminal associated with the process</li>
<li><strong>STAT</strong>: The process state (Running, Sleeping, Zombie, and so on.)</li>
<li><strong>START</strong>: The start time of the process</li>
<li><strong>TIME</strong>: The CPU time used</li>
<li><strong>COMMAND</strong>: The command that started the process</li>
</ul>
<p>You can also filter the Ps output by:</p>
<ul>
<li>Username: <code>ps aux | grep root</code></li>
<li>Process name: <code>ps aux | grep cron</code></li>
<li>PID: <code>ps aux | grep 555</code></li>
</ul>
<p>The Ps command allows you to quickly check in on what your system is doing and ensure there are no runaway or zombie processes hogging resources. For any Linux user, <code>Ps</code> is an indispensable tool for system monitoring and troubleshooting.</p>
<h2 id="heading-rsync-sync-files-and-folders">Rsync: Sync Files and Folders</h2>
<p>As a Linux user, you’ve probably found yourself needing to sync files and folders between locations. Maybe you have files on your desktop you need to transfer to your laptop, or you want to backup your most important folders to an external drive. The rsync command makes syncing and backing up your files a breeze.</p>
<p>Rsync is a fast and versatile file copying tool. It can copy and sync files and folders locally or remotely over SSH. It’s smart enough to only transfer the differences between two locations, saving time and bandwidth.</p>
<p>To use rsync, open your terminal and enter the command:</p>
<pre><code class="lang-bash">rsync [options] <span class="hljs-built_in">source</span> destination
</code></pre>
<ul>
<li>The source is the location of the files you want to copy. This could be a folder on your desktop or a remote server.</li>
<li>The destination is where you want to copy the files. This could be an external drive mounted on your system or a folder on another server.</li>
<li>Options allow you to specify items like:</li>
<li><code>-a</code>: Archive mode which preserves permissions, timestamps, group, owner and symlinks</li>
<li><code>-v</code>: Verbose output so you can see what’s being copied</li>
<li><code>-z</code>: Compression to speed up transfers over slow networks</li>
<li>-h: Human-readable sizes (e.g. 1K, 234M, 2G)</li>
</ul>
<p>Rsync is a must-have tool for any Linux user. Once you get the hang of it, you’ll be syncing and backing up your files with confidence. </p>
<p>For broad reading please refer to <a target="_blank" href="https://www.freecodecamp.org/news/rsync-examples-rsync-options-and-how-to-copy-files-over-ssh/">RSync Examples – Rsync Options and How to Copy Files Over SSH</a>.</p>
<h2 id="heading-the-powerful-pipe-viewer-pv">The Powerful Pipe Viewer (pv)</h2>
<p>Ever wanted to see the progress of data through a pipe? The <code>pv</code> command allows you to do just that. It's a pipe viewer that shows you the progress of data through a pipeline.</p>
<p>Say you have a large file that you want to compress, like a video or backup file. Rather than staring at a blinking cursor while gzip does its thing, you can see the progress with pv. Just pipe the data through pv, then to gzip:</p>
<pre><code class="lang-bash">cat mylargefile.mp4 | pv | gzip &gt; mylargefile.mp4.gz
</code></pre>
<p><code>pv</code> will display the throughput and estimated time remaining as your data is compressed. It's a simple way to get feedback on long-running commands.</p>
<p>You can also use <code>pv</code> to see <a target="_blank" href="https://www.techtarget.com/searchnetworking/definition/throughput#:~:text=Throughput%20is%20a%20measure%20of,and%20network%20systems%20to%20organizations.">throughput</a> and transfer rates of data over the network. For example, when copying a file with <code>scp</code> or <code>rsync</code>, add <code>pv</code> to the pipeline:</p>
<pre><code class="lang-bash">rsync -avz myfiles user@host:/backup | pv
</code></pre>
<p>Now you'll see the progress of your files copying over the network. pv gives you information like:</p>
<ul>
<li>Transferred bytes</li>
<li>Transfer rate</li>
<li>ETA</li>
<li>Progress</li>
<li>And more</li>
</ul>
<p>It's a handy tool to give you more insight into what's happening in those long-running terminal commands.</p>
<h2 id="heading-mtr-network-diagnostics">mtr: Network Diagnostics</h2>
<p>Have you ever needed to diagnose network issues but didn’t have access to expensive tools? mtr is a simple but powerful Linux network diagnostic tool. It combines the functionality of the ‘traceroute’ and ‘ping’ programs in a single network diagnostic tool.</p>
<p><code>mtr</code> sends <a target="_blank" href="https://www.freecodecamp.org/news/traceroute-and-ping/">ICMP</a> echo requests to test the network connectivity between the host <code>mtr</code> runs on and a user-specified destination host. It prints the response times and packet loss statistics for each router along the path. This allows you to quickly pinpoint network issues.</p>
<p>To use mtr, open a terminal and enter:</p>
<pre><code class="lang-bash">mtr [domain name or IP address]
</code></pre>
<p>For example, to trace the route to google.com, enter:</p>
<pre><code class="lang-bash">mtr google.com
</code></pre>
<p>mtr will start tracing the route and printing results that update in real time. It will show:</p>
<ul>
<li>The IP address and hostname of each router along the path</li>
<li>The percentage of packet loss for each router</li>
<li>The response times in milliseconds for each router</li>
</ul>
<p>The output will continue to update until you press Ctrl+C to stop the trace.</p>
<p>mtr is a simple but useful tool for any Linux network administrator. It can save you hours of troubleshooting time when the network goes down by helping you identify the source of latency or packet loss.</p>
<h2 id="heading-jq-parse-json">jq: Parse JSON</h2>
<p>Ever come across a messy JSON file and wish you had an easy way to parse through it? Meet jq, a command line tool that lets you filter and analyze JSON data with ease.</p>
<p>jq works like a filter. You pass it JSON data on stdin, and it passes the filtered/transformed data to stdout. </p>
<p>For example, say you have a JSON file called <code>data.json</code> with an array of objects. You can filter it to only show objects where <code>name</code> is equal to <code>John</code> like this:</p>
<pre><code class="lang-bash">cat data.json | jq <span class="hljs-string">'.[] | select(.name == "John")'</span>
</code></pre>
<p>This will print only the John objects to the console.</p>
<p>jq supports many more filters than just <code>select()</code>, here are a few more useful ones:</p>
<ul>
<li><code>.key</code>: Access a key from objects</li>
<li><code>.[10:]</code>: Show elements from index 10 onwards</li>
<li><code>.[10:15]</code>: Show elements from index 10 to 15</li>
<li><code>length</code>: Print the length of an array</li>
<li><code>map(.)</code>: Apply a filter to each element of an array</li>
<li><code>group_by(.key)</code>: Group objects by a key</li>
</ul>
<p>With jq, you can manipulate JSON data in pretty much any way you want right from the command line. <code>jq</code> may seem niche, but JSON is used everywhere on the web, so being able to analyze and transform it efficiently is a useful skill.</p>
<h2 id="heading-tac-view-config-files-in-reverse">tac: View Config Files in Reverse</h2>
<p>Have you ever made a mistake while editing a config file and saved the changes, only to realize you preferred the previous version? The <code>tac</code> command allows you to quickly view config files in reverse, so you can see what the file looked like before your edits.</p>
<p>Tac simply prints files in reverse order, line by line. To view a file called <code>config.txt</code> in reverse, run:</p>
<pre><code class="lang-bash">tac config.txt
</code></pre>
<p>This will print the last line of the file first, then the second last line, and so on until it reaches the first line.</p>
<ul>
<li>Use tac when you want to <strong>quickly view a log file in reverse</strong> to see the latest entries first.</li>
<li>Tac can also be useful when <strong>editing config files through the command line</strong>. If you make a mistake, run tac to see what the file looked like before so you can revert your changes.</li>
</ul>
<p>Tac is a simple but useful utility to have in your Linux toolkit.</p>
<h2 id="heading-perf-analyze-cpu-performance">perf: Analyze CPU Performance</h2>
<p>If you've ever wondered why your Linux system seems slower over time, the perf command can help you figure it out. Perf is a profiling tool in Linux that can analyze the performance of your CPU to help identify any bottlenecks.</p>
<p>To get started, run the basic <code>perf list</code> command to see a list of the events you can monitor. There are hundreds! Some of the most useful ones for profiling CPU performance are:</p>
<ul>
<li><code>cpu-clock</code>: Measure the CPU clock cycles</li>
<li><code>task-clock</code>: Measure the time spent on task execution</li>
<li><code>cache-misses</code>: Count the number of cache misses</li>
<li><code>branch-misses</code>: Count the number of branch prediction misses</li>
</ul>
<p>Pick an event you want to monitor, then run a command like:</p>
<pre><code class="lang-bash">perf <span class="hljs-built_in">stat</span> -e cpu-clock sleep 5
</code></pre>
<p>This will run the <code>sleep 5</code> command and measure the <code>cpu-clock</code> event while it's running. Perf will then give you a summary of the stats for that event.</p>
<p>To get more detailed profiling info, use the <code>perf record</code> command. For example, to profile a script called <code>script.sh</code>, run:</p>
<pre><code class="lang-bash">perf record script.sh
</code></pre>
<p>This will run the script and record the profiling data. You can then view the results with:</p>
<pre><code class="lang-bash">perf report
</code></pre>
<p>This gives you an interactive report to analyze the results. You'll see things like:</p>
<ul>
<li>The percentage of time spent in each function</li>
<li>The actual time spent in each function</li>
<li>The number of calls to each function</li>
</ul>
<p>Using perf, you have a powerful tool to optimize the performance of your Linux system. Perf really is an amazing (if underused) tool.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>So there you have it, some helpful Linux commands that will make you feel like a power user in no time. </p>
<p>With these tricks up your sleeve, you'll be zipping around Linux like a pro. The next time you're stuck or frustrated, give one of these a shot. You might just surprise yourself with what you can accomplish.</p>
<p>Linux is an incredibly powerful operating system if you know how to speak its language. Consider this your starter guide to becoming fluent.</p>
<p>I am <a target="_blank" href="https://rahul.biz/">Rahul</a>, 19, Hustler. I am building <a target="_blank" href="https://fueler.io/register?referral_token=94329340-3e14-4e1e-83fa-bd5e1992">Fueler.io</a> a platform for generalists to create proof of work profile and land opportunities. Let’s connect on <a target="_blank" href="https://twitter.com/rahul_wip">Twitter</a>.  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create and Manage Virtual Machines with the Vagrant Command Line Tool ]]>
                </title>
                <description>
                    <![CDATA[ Creating and managing virtual machines used to be a tedious and time-consuming process. Replicating the VM on a different server can also be challenging, and it gets harder if you have to replicate multiple VMs. But then Vagrant came along, a command... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-and-manage-virtual-machines-with-vagrant/</link>
                <guid isPermaLink="false">66d45f31246e57ac83a2c76b</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ virtual machine ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Eti Ijeoma ]]>
                </dc:creator>
                <pubDate>Mon, 03 Apr 2023 20:15:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/Screenshot-2023-04-01-at-23.42.01-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Creating and managing virtual machines used to be a tedious and time-consuming process. Replicating the VM on a different server can also be challenging, and it gets harder if you have to replicate multiple VMs.</p>
<p>But then Vagrant came along, a command-line or shell tool that generally works with <a target="_blank" href="https://en.wikipedia.org/wiki/Hypervisor#:~:text=Type%2D2%20or%20hosted%20hypervisors">Type 2 hypervisors</a>. You use it to create and manage virtual machines. It is a powerful tool that can help simplify the setup and management of your development environment.</p>
<p>Vagrant can be really helpful if you work on a team or with multiple people. This is because it guarantees consistency in your development environment by ensuring that everyone utilizes the same environment, preventing compatibility issues.</p>
<p>This tutorial will guide you through the process of setting up a single Ubuntu Linux virtual machine with Vagrant and configuring a web server inside it.</p>
<h3 id="heading-prerequisites-for-this-tutorial-include">Prerequisites for this tutorial include:</h3>
<ul>
<li><p>A computer with at least 8GB of RAM</p>
</li>
<li><p>Basic knowledge of the Linux operating system</p>
</li>
</ul>
<h3 id="heading-required-tools-and-installation">Required Tools and Installation</h3>
<ul>
<li><p><strong>Oracle VirtualBox:</strong> Go to the <a target="_blank" href="https://www.virtualbox.org/wiki/Downloads">Oracle VirtualBox</a> website, find the version of VirtualBox that is compatible with your operating system, and follow the instructions to download and install it. Virtual Box will provide the virtual environment, while Vagrant will set it up and manage it.</p>
</li>
<li><p><strong>Vagrant:</strong> Visit the <a target="_blank" href="https://www.vagrantup.com/">Vagrant website</a> and follow the instructions to download and install the binary that is suitable for your operating system. In this tutorial, we'll be utilizing the open-source Vagrant binary.</p>
</li>
</ul>
<p>To check if the installation was successful, launch your preferred command line tool and enter the following command to output the installed version number:</p>
<pre><code class="lang-bash">$ vagrant --version
</code></pre>
<h2 id="heading-how-to-create-a-development-environment-with-vagrant">How to Create a Development Environment with Vagrant</h2>
<p>To create a Vagrant project, start by creating a new project directory in your preferred location for Vagrant configuration and related files.</p>
<pre><code class="lang-bash">$ mkdir vagrant-project &amp;&amp; <span class="hljs-built_in">cd</span> vagrant-project
</code></pre>
<p>Within this directory, create a new Vagrantfile. Vagrant uses the configuration in the Vagrantfile to build the VM. By default, Vagrant syncs the project directory where the Vagrantfile is initialized to /vagrant. This eliminates the need to worry about volumes for persisting data.</p>
<p>Vagrant uses the concept of boxes. Boxes are a complete base image of an operating system. The public <a target="_blank" href="https://app.vagrantup.com/boxes/search">vagrant box repository</a> contains a list of possible boxes. Choosing a box that matches the operating system used in your production environment is good practice.</p>
<p>A Vagrant box has the name of the user or organization that created it and the box name <code>user/boxname</code>. To initialize the Vagrant configuration file with an Ubuntu box, run the command:</p>
<pre><code class="lang-bash">$ vagrant init ubuntu/trusty64
</code></pre>
<p>This generates a Vagrantfile with a Ubuntu/trusty64 box in the current directory. The Vagrantfile, which is written in Ruby, contains the kind of VM to be used and various additional commented options such as network, port forwarding, disc capacity, and so on to assist in configuring the development environment.</p>
<p>You can add the <code>--minimal</code> flag to the initialization command of the Vagrantfile to generate a Vagrantfile without any additional settings.</p>
<p>Open the Vagrantfile with any editor of your choice. I will use the Vim editor in this tutorial.</p>
<pre><code class="lang-bash"> $ vim Vagrantfile
</code></pre>
<p>Removing the informational comments and some advanced configurations will leave the file like this:</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># -*- mode: ruby -*-</span>
<span class="hljs-comment"># vi: set ft=ruby :</span>

Vagrant.configure(<span class="hljs-string">"2"</span>) <span class="hljs-keyword">do</span> <span class="hljs-params">|config|</span>
  config.vm.box = <span class="hljs-string">"ubuntu/xenial64"</span>
    config.vm.network <span class="hljs-string">"forwarded_port"</span>, <span class="hljs-symbol">guest:</span> <span class="hljs-number">8000</span>, <span class="hljs-symbol">host:</span> <span class="hljs-number">8000</span>
    config.vm.provider <span class="hljs-string">"virtualbox"</span> <span class="hljs-keyword">do</span> <span class="hljs-params">|vb|</span> vb.memory = <span class="hljs-string">"1024"</span>
 <span class="hljs-keyword">end</span>
  config.vm.provision <span class="hljs-symbol">:shell</span>, <span class="hljs-symbol">path:</span> <span class="hljs-string">"simple-node-project.sh"</span>, <span class="hljs-symbol">privileged:</span> <span class="hljs-literal">false</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>The <code>simple-node-project.sh</code> is a bash script that installs Node.js and Git, clones a project that creates a simple Node.js web server, and starts the server.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

 sudo apt-get update -y

 <span class="hljs-comment">## Git ##</span>
 <span class="hljs-built_in">echo</span> <span class="hljs-string">'###Installing Git..'</span>
 sudo apt-get install git -y

 git <span class="hljs-built_in">clone</span> https://github.com/Aijeyomah/simple-node-app.git

<span class="hljs-comment"># Installing latest Node and npm version</span>
 sudo apt-get install -y curl software-properties-common

<span class="hljs-comment"># Add Node.js PPA</span>
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -

<span class="hljs-comment"># Install Node.js and npm</span>
sudo apt-get install -y nodejs

<span class="hljs-comment"># Verify installation</span>
node -v
npm -v

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Node.js has been installed successfully."</span>

<span class="hljs-comment"># navigate to app directory and start app</span>
<span class="hljs-built_in">cd</span> simple-node-app
node index.js &amp;
</code></pre>
<p>This Vagrant configuration sets up the following:</p>
<ul>
<li><p><code>ubuntu/trusty64</code> is specified as the virtual box base image</p>
</li>
<li><p>Forwards port 8000 of the VM to port 8000 of the host machine.</p>
</li>
<li><p>Allocates 1GB of memory to the VM</p>
</li>
<li><p>Runs <code>simple-node-project</code> to provision the VM</p>
</li>
<li><p>For the shell provisioner to run the script as a non-root user in a login shell, <code>privileged</code> is set to <code>false</code></p>
</li>
</ul>
<p>Save the <code>Vagrantfile</code> and start the virtual machine by running the following command:</p>
<pre><code class="lang-bash">$ vagrant up
</code></pre>
<p>The first time this command is run, it will download the latest version of the specified box, and it will configure and start the VM. This process might take some time, but when the Ubuntu box exists in the local machine the VM will start immediately.</p>
<p>Once the VM is running, you can access the web page by opening a web browser and navigating to <a target="_blank" href="http://localhost:8080"><code>http://localhost:8000</code></a>. You should see the <code>Hello World</code> message page if everything was set up correctly.</p>
<h2 id="heading-how-to-manage-vagrant">How to Manage Vagrant</h2>
<p>You can use Vagrant to manage the running virtual machine. Here are some useful Vagrant commands:</p>
<p><code>vagrant up</code>: Launches the virtual machine and provisions it according to the settings in the Vagrantfile. This command will simply connect to the virtual machine if it is already running.</p>
<p><code>vagrant halt</code>: Stops the virtual machine by delivering a shutdown signal to the guest operating system. This command is similar to shutting down a real computer.</p>
<p><code>vagrant reload</code>: Restarts the virtual machine and re-provisions it depending on any changes in the Vagrantfile.</p>
<p><code>vagrant ssh</code>: Connects to the virtual machine via SSH. This command is useful for accessing the command line interface of the virtual machine.</p>
<p><code>vagrant status</code>: Shows the current status of the virtual machine, including whether it's running, stopped, or suspended.</p>
<p><code>vagrant destroy</code>: Deletes the virtual machine and all associated resources. This command is useful for cleaning up your development environment.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we have learned how to utilize Vagrant to set up a reproducible and consistent development environment.</p>
<p>Using Vagrant can help you set up a virtual development environment that closely mimics your production environment. This allows you to test and develop your code in a consistent and isolated environment.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a CRUD Command Line Application With Node.js ]]>
                </title>
                <description>
                    <![CDATA[ By Njoku Samson Ebere If you're looking for a tutorial to teach you the basics of Nodejs and the command line, you're in the right place.   You can use JavaScript to build almost any software (web, mobile, bots, and so on). The reason is that compute... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-command-line-application-with-nodejs/</link>
                <guid isPermaLink="false">66d84fa4c15439a8d5631e6d</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 06 Feb 2023 15:59:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/pexels-hitesh-choudhary-1261427.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Njoku Samson Ebere</p>
<p>If you're looking for a tutorial to teach you the basics of <a target="_blank" href="https://nodejs.org/en/">Nodejs</a> and the command line, you're in the right place.  </p>
<p>You can use JavaScript to build almost any software (web, mobile, bots, and so on). The reason is that computers no longer depend on browsers only to understand JavaScript code. Check out this article to see <a target="_blank" href="https://dev.to/ebereplenty/how-computers-understand-javascript-code-k1n">How Computers Understand JavaScript Code</a>. </p>
<p>Node.js is used to run backend applications that are written in JavaScript.   </p>
<p>I will teach you how to build a command line application that can read, write, edit, and delete data using Node.js. It will not require connecting to external databases like MySQL, MongoDB, Postgresql, and so on. See the project <a target="_blank" href="https://github.com/EBEREGIT/Nodejs_CLI_app">here</a>.  </p>
<p>By the end of the article, you should be able to set up a basic Node project, manipulate files, use modules, navigate promises, collect input, and so on.</p>
<p>I also added videos to enhance your learning.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You do not need any prior programming knowledge to understand this tutorial.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/RQ4b0Ui1-3o" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-the-finished-project-will-function">How the Finished Project Will Function</h2>
<p>The application that we are going to build will be able to do the following:</p>
<ul>
<li>Check if a database exists</li>
<li>Retrieve data from the database</li>
<li>Add new data to the database</li>
<li>Update database with new data</li>
<li>Remove data from the database</li>
</ul>
<h2 id="heading-how-to-install-node-and-npm">How to Install Node and NPM</h2>
<p>Please go to the <a target="_blank" href="https://nodejs.org/en/">Nodejs website</a> and download the one recommended for all users. Install it after the download is complete.</p>
<p>Use the command below to check if the installation was successful:</p>
<ul>
<li>For Node</li>
</ul>
<pre><code>node -v
</code></pre><ul>
<li>For npm</li>
</ul>
<pre><code>npm -v
</code></pre><p>The installation is successful if each command returns a version number.</p>
<h2 id="heading-how-to-setup-a-nodejs-project">How to Setup a  Node.js Project</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/8dlICKn-tQw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>The steps below will help you set up your project:  </p>
<p>Open your terminal or CMD and create the project directory:</p>
<pre><code>mkdir node_CLI_app
</code></pre><p>Navigate into the directory:</p>
<pre><code>cd node_CLI_app
</code></pre><p>Initialize the project:</p>
<pre><code>npm init
</code></pre><p>It will bring up some questions. Press the Enter button for every prompt.   </p>
<p>A new file (<code>package.json</code>) should have been added to your project directory. We will use the file to add external code (module) to the project.  </p>
<p>Add the following line before the closing curly brace (<code>}</code>) to enable ES6 import:</p>
<pre><code><span class="hljs-string">"type"</span>: <span class="hljs-string">"module"</span>
</code></pre><p>That completes the project setup!</p>
<h2 id="heading-how-to-install-dependencies">How to Install Dependencies</h2>
<p>You will recall that the <code>package.json</code> file is for adding external code to the project. This external code is also called Dependencies, Modules, or Packages. It's written by other programmers (usually free of charge) to help others build applications faster. You will find a lot of these on the <a target="_blank" href="https://www.npmjs.com/">npm website</a>.  </p>
<p>We need two (2) packages for this project: <a target="_blank" href="https://www.npmjs.com/package/inquirer">inquirer</a> and <a target="_blank" href="https://www.npmjs.com/package/uuid">uuid</a>. I will show you how to install them in this section.  </p>
<p>Installing of packages follows this pattern:</p>
<pre><code>npm install &lt;package_name&gt;
</code></pre><p>We can install more than one package at a time by separating the package names with a space:</p>
<pre><code>npm install &lt;package_name_1&gt; &lt;package_name_2&gt; &lt;package_name_3&gt;
</code></pre><p>The <code>install</code> command can be replaced with <code>i</code> for convenience.  </p>
<p>So run the following command to install the packages:</p>
<pre><code>npm i inquirer uuid
</code></pre><p>Your package.json file should have the following lines of code added to it when the installation is complete:</p>
<pre><code class="lang-javascript">
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"inquirer"</span>: <span class="hljs-string">"^9.1.4"</span>,
    <span class="hljs-string">"uuid"</span>: <span class="hljs-string">"^9.0.0"</span>
  }
</code></pre>
<p>The version numbers may differ, but that’s fine.</p>
<p>You will also notice that a file (<code>package.lock.json</code>) and a folder (<code>node_modules</code>) have been added. You do not have to worry about them. Just know that they help to manage the external code we just added.</p>
<p>That completes the installation of dependencies!</p>
<h2 id="heading-how-to-create-a-new-file-from-the-terminal">How to Create a New File from the Terminal</h2>
<p>You can create a file from the terminal using the following command:</p>
<ul>
<li>On Mac:</li>
</ul>
<pre><code>touch &lt;file_name&gt;
</code></pre><ul>
<li>On Windows:</li>
</ul>
<pre><code>echo.&gt;<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">file_name</span>&gt;</span></span>
</code></pre><p>You can also create more than one file at a time by separating the files with a space. That is how we will generate the files for this project:</p>
<pre><code>touch addData.js removeData.js retrieveData.js updateData.js queryDB.js dbFileCheck.js
</code></pre><p>Each of those files will play a unique role in the application.</p>
<ul>
<li><code>addData.js</code> adds data to the database. It also fabricates the database file if it doesn’t exist.</li>
<li><code>removeData.js</code> removes selected data.</li>
<li><code>retrieveData.js</code> fetches all data.</li>
<li><code>updateData.js</code> edits data.</li>
<li><code>queryDB.js</code> checks if a database exists and executes a function passed to it.</li>
<li><code>dbFileCheck.js</code> confirms if the database file has been created.</li>
</ul>
<p>There is one more file that we did not create: the database file (<code>db.json</code>). We will auto-generate it using our code.</p>
<h2 id="heading-how-to-check-if-a-file-exists">How to Check if a File Exists</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/V9dmEXCnY-8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Node.js provides a built-in module for manipulating files – <a target="_blank" href="https://nodejs.org/api/fs.html">file system</a> (fs). One of the methods that the module contains is the <code>existsSync</code> method. It returns <code>true</code> or <code>false</code> depending on if the file has been created. I will use that to check if the <code>db.json</code> file is in the project. See the code below:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
  <span class="hljs-keyword">import</span> { exit } <span class="hljs-keyword">from</span> <span class="hljs-string">"process"</span>;  

  <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"File exists!"</span>);
    exit(<span class="hljs-number">1</span>);
  }
</code></pre>
<p>The <code>exit</code> method terminates a process.</p>
<p>That is what we want to do in the <code>dbFileCheck.js</code> file. However, we want to invert the result by adding a <code>!</code> before the <code>fs.existsSync</code> method like this:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
  <span class="hljs-keyword">import</span> { exit } <span class="hljs-keyword">from</span> <span class="hljs-string">"process"</span>;  

  <span class="hljs-keyword">if</span> (!fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"File does not exist!"</span>);
    exit(<span class="hljs-number">1</span>);
  }
</code></pre>
<p>This will be necessary when building other functionalities like updating and deleting data. </p>
<p>So how will those files gain access to this code? It is through a modular structure. That entails bundling this code and making it accessible through other files in the project. The export command makes this possible:</p>
<pre><code><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> { exit } <span class="hljs-keyword">from</span> <span class="hljs-string">"process"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dbFileCheck</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">if</span> (!fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Database is Empty. Create some data!"</span>);
    exit(<span class="hljs-number">1</span>);
  }
}
</code></pre><p>The code above puts the code in a function (<code>dbFileCheck</code>) and exports it using the <code>export</code> command. This function can now be imported and used in other files within this project.</p>
<p>Note that the <code>default</code> keyword is necessary for the first export from a file.</p>
<h2 id="heading-how-to-query-the-database">How to Query the Database</h2>
<p>Another method the <code>file system</code> has is the <code>readFile</code> method. It returns the content of any file passed to it. </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/ZmckWr9sH-w" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>The <code>readFile</code> method takes in two parameters: the file to be read and a callback function that returns the result of the operation.  </p>
<p>We will use the following code to retrieve data from our database:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  }
  <span class="hljs-built_in">console</span>.log(data.toString());
});
</code></pre>
<p>The code above imports the file system module and tries to read the database file. If there is an error, it will return the error. If there are no errors, it will return the data it got. </p>
<p>The <code>.toString()</code> method attached to the data returned (<code>data.toString()</code>) is because the data retrieved is of the type <code>buffer</code> by default, which is not readable.</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074450995_Screenshot+2023-01-30+at+11.25.25.png" alt="Image" width="2654" height="107" loading="lazy">
<em>buffer output</em></p>
<p>Open your project in a code editor and paste that code into the <code>queryDB.js</code> file.  </p>
<p>Run the command below to see if it is working:</p>
<pre><code>node queryDB
</code></pre><p>The command above will execute every code in the <code>queryDB.js</code>. The <code>.js</code> extension is optional. It will run either way.</p>
<p>The result of that operation will be an error because we do not have the file.</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074558543_Screenshot+2023-01-30+at+11.28.47.png" alt="Image" width="1515" height="344" loading="lazy"></p>
<p>You can create the <code>db.json</code> file, add some content, and check the output.  </p>
<p>But we do not want our app to try to read the database file if it has not been generated. So use the <code>existsSync</code> method to check if the file has been created. See how I use it in the code below:</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(err);
        }
        <span class="hljs-built_in">console</span>.log(data.toString());
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No data available!"</span>);
    }
</code></pre>
<p>The code above checks if the file exists by passing the file name (<code>db.json</code>) to the <code>fs.existsSync</code> method. If it is true, then it reads the file. If it is false, it returns a string.</p>
<p>Now that we have that clean code, we want to make it even more robust.</p>
<p>Since we are building a CRUD application, we must have access to and keep track of the data returned. I have introduced a new variable in the code below to make that happen:</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

    <span class="hljs-keyword">let</span> info = [];
    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(err);
        }
        info = <span class="hljs-built_in">JSON</span>.parse(data.toString());
        <span class="hljs-built_in">console</span>.log(info);
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No data available!"</span>);
    }
</code></pre>
<p>The code above now has a variable, <code>info</code>. It keeps track of the data returned. I passed the data through the <code>JSON.parse</code> method to convert the data from string to array. </p>
<p>We can now manipulate the <code>info</code> as we deem fit. We have to export the code and accept a function to make this possible. That function will take the <code>info</code> variable as input and then use it as required.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">queryDB</span>(<span class="hljs-params">externalFunction</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">let</span> info = [];

    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      <span class="hljs-keyword">await</span> fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
        info = <span class="hljs-built_in">JSON</span>.parse(data.toString());
        <span class="hljs-built_in">console</span>.log(info);

        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(err);
          <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-keyword">if</span> (externalFunction &amp;&amp; !err) {
          externalFunction(info);
          <span class="hljs-keyword">return</span>;
        }
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">if</span> (externalFunction) {
        externalFunction(info);
        <span class="hljs-keyword">return</span>;
      }
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Something Happened: <span class="hljs-subst">${error.message}</span>`</span>);
  }
}
</code></pre>
<p>This code takes in a function and executes it only if there are no errors. However, there will be one exception – when adding data. In that case, the database will be created.</p>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch"><code>try…catch…</code></a> block helps pick out errors, and the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code></a> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>await</code></a> keywords are used when executing code that will take a long time to run.</p>
<p>The <code>queryDB.js</code> will no longer return any output when we execute the <code>node queryDB</code> command. But that is fine. We will trigger it from other files.</p>
<h2 id="heading-how-to-add-data-to-a-file">How to Add Data to a File</h2>
<p>In this section, I will teach you how to add data to the store. The file for this section is the <code>addData.js</code> file.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/vi0unBmidkE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>We will start by importing all necessary modules:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">"uuid"</span>;
<span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;
</code></pre>
<p>Next, create the boilerplate for the function:</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addData</span>(<span class="hljs-params">info</span>) </span>{
  <span class="hljs-keyword">try</span> {

  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>This is similar to what we have done before now. All the code we would write next will go into the <code>try…</code> block. The <code>info</code> array passed into the function is coming from the <code>queryDB</code> file.  </p>
<p>The first thing to do in the <code>try…</code> block is to collect the data to be stored. We will use <a target="_blank" href="https://www.npmjs.com/package/inquirer"><code>inquirer</code></a> to do that with the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"name"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your name?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"number"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"phone"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your phone?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"list"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"age"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Are you an adult?"</span>,
        <span class="hljs-attr">choices</span>: [
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"Y"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Adult"</span> },
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"N"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Minor"</span> },
        ],
      },
    ]);
</code></pre>
<p>The <code>inquirer</code> package helps in building interactive command line interfaces. It contains a method called <code>prompt</code> used to ask for inputs. It takes an array of questions in object format. Each object must have the <code>name</code>, <code>type</code>, and <code>message</code> keys. </p>
<p>The <code>choices</code> key is optional. It is used when there is a list of options.</p>
<p>So the code above collects three (3) inputs (name, phone, and age) and stores them in a variable called <code>answers</code>.</p>
<p>Next, we assign this set of input a unique ID by calling the <code>uuidv4()</code> function and push everything into the <code>info</code> array:</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">const</span> data = {
      <span class="hljs-attr">id</span>: uuidv4(),
      <span class="hljs-attr">name</span>: answers.name,
      <span class="hljs-attr">phone</span>: answers.phone,
      <span class="hljs-attr">age</span>: answers.age,
    };
    info.push(data);
</code></pre>
<p>Finally, we check if the database file exists. We will update the database with the new data if the file has been created or create it and add the new data if it is false.</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      createDetails(info);
    } <span class="hljs-keyword">else</span> {
      fs.appendFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-string">"[]"</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Could not create db.json"</span>, err);
          <span class="hljs-keyword">return</span>;
        }
        createDetails(info);
      });
    }
</code></pre>
<p>The <code>createDetails</code> function will be used to overwrite the database data. I will create that in a bit.  </p>
<p>In the <code>else</code> (if the file doesn’t exist) block, I created the file using the file system’s <code>appendFile</code> method. This method is used to create a file if it is not there already and add or append data to the bottom of the file. </p>
<p>I am appending <code>[]</code> to the file. So the newly created file will have just <code>[]</code> in it. I called the <code>createDetails</code> function next to add the data collected from the CLI.  </p>
<p>Please type the following code for the createDetails function below the addData function. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createDetails</span>(<span class="hljs-params">info</span>) </span>{
  <span class="hljs-keyword">await</span> fs.writeFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(info), <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
      <span class="hljs-built_in">console</span>.log(err);
    }
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"saved!"</span>);
  });
}
</code></pre>
<p>This function uses the file system’s <code>writeFile</code> method to overwrite the database with current data. I am using <code>JSON.stringify</code> to convert the <code>info</code> variable to a string because that is the acceptable format when writing to a file. That also explains why I used <code>JSON.parse</code> to convert it to the original type when I retrieved it in the previous section.  </p>
<p><code>writeFile</code> is different from <code>appendFile</code> because <code>writeFile</code> overwrites a file while <code>appendFile</code> adds to the existing content. They are similar in that both methods will create the file if it has not been created.</p>
<p>The last thing to do in this file is invoke or call the function. The way to do that is by typing its name followed by opening and closing braces like this:</p>
<pre><code class="lang-javascript">addData();
</code></pre>
<p>This might work fine, but it wouldn’t do what we want. We need to pass the function as an argument into the <code>queryDB</code> like this:</p>
<pre><code class="lang-javascript">queryDB(addData);
</code></pre>
<p>Now, the <code>addData</code> will be able to communicate with the <code>queryDB</code> function.</p>
<h2 id="heading-how-to-test-the-adddata-file">How to Test the <code>addData</code> File</h2>
<p>Run the command below to test if the <code>addData</code> file works as expected:</p>
<pre><code>node addData
</code></pre><p>It will prompt you for answers. Fill in the answers. After that, your screen should look like mine:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675241012883_Screenshot+2023-02-01+at+09.42.57.png" alt="Image" width="1057" height="236" loading="lazy">
<em>addData output</em></p>
<p>It should also have auto-generated a <code>db.json</code> file with the data you just added.</p>
<p>And that is it for the <code>addData</code> file!</p>
<h2 id="heading-how-to-retrieve-data">How to Retrieve Data</h2>
<p>This section shows how to get the content of the database. All you need to achieve this functionality is the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;

queryDB();
</code></pre>
<p>What the code does is import the <code>queryDB</code> function and invoke it. Paste the code in the <code>retrieveData.js</code> file and execute the file with:</p>
<pre><code>node retrieveData
</code></pre><p>It will return an output similar to this:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675319554801_Screenshot+2023-02-02+at+07.29.43.png" alt="Image" width="1162" height="389" loading="lazy">
<em>retrieveData.js output</em></p>
<p>You might wonder: why did I not call this function in the <code>queryDB</code> file? The reason is that the file performs more than just retrieving data. Calling the <code>queryDB</code> function in its file will alter the result of other files.</p>
<h2 id="heading-how-to-edit-data">How to Edit Data</h2>
<p>This section will now focus on how to update data. The pattern to follow here is:</p>
<ul>
<li>Collect the user’s ID.</li>
<li>Search for the user.</li>
<li>Return the user’s data if the user exists, and set it as the default option.</li>
<li>Ask for updated info. The initial value will be kept if the user presses the <code>Enter</code> key.</li>
<li>Finally, overwrite the database with the updated information.</li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/UmshAmmU-44" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Let’s get to it…  </p>
<p>Navigate into the <code>updateData.js</code> file and paste the following code:</p>
<pre><code><span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;
<span class="hljs-keyword">import</span> dbFileCheck <span class="hljs-keyword">from</span> <span class="hljs-string">"./dbFileCheck.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateData</span>(<span class="hljs-params">info</span>) </span>{
  dbFileCheck();

  <span class="hljs-keyword">try</span> {

  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>This is the boilerplate for the <code>updateData</code> function. The new thing here is the <code>dbFileCheck</code> function (made it a while ago) to terminate an operation if the database has not been created.   </p>
<p>The rest of the code will be inside the <code>try…</code> block.</p>
<p>The first thing is to collect the user ID with this code:</p>
<pre><code>    <span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"recordID"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Enter Record ID"</span>,
      },
    ]);
</code></pre><p>The second is to search for the user:</p>
<pre><code>    <span class="hljs-keyword">let</span> current;

    info.forEach(<span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (element.id === answers.recordID) {
        current = element;

        updateDetails(current, info);
      }
    });
</code></pre><p>The code above searches through the users (<code>info</code>) and sets the user found to the <code>current</code> variable. Finally, the <code>updateDetails</code> is called to collect the updated information and overwrite the database with the new data.</p>
<h3 id="heading-how-to-build-the-updatedetails-function">How to build the <code>updateDetails</code> function</h3>
<p>This part will show how to keep track of a user’s initial data while collecting new data. It will update the database with the new data afterward.  </p>
<p>The following code is the boilerplate for the function:</p>
<pre><code><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateDetails</span>(<span class="hljs-params">current, info</span>) </span>{
  <span class="hljs-keyword">try</span> {

  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>This code goes under the <code>updateData</code> operation.  </p>
<p>The code below goes into the <code>try…</code> block. It is for collecting updated information from the user.</p>
<pre><code>  <span class="hljs-keyword">const</span> feedbacks = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">default</span>: current.name,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"name"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your name?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"number"</span>,
        <span class="hljs-attr">default</span>: current.phone,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"phone"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your phone?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"list"</span>,
        <span class="hljs-attr">default</span>: current.age,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"age"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Are an adult?"</span>,
        <span class="hljs-attr">choices</span>: [
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"Y"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Adult"</span> },
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"N"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Minor"</span> },
        ],
      },
    ]);
</code></pre><p>The <code>default</code> key is new. It holds input that will be used if the user doesn’t provide one. It keeps track of the user’s current data for this code. So the user can hit the <code>Enter</code> button instead of entering the former value again.  </p>
<p>The user’s details should be updated accordingly using this code:</p>
<pre><code>    current.name = feedbacks.name;
    current.phone = feedbacks.phone;
    current.age = feedbacks.age;
</code></pre><p>Finally, overwrite the database with the new value:</p>
<pre><code><span class="hljs-keyword">await</span> fs.writeFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(info), <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
      <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.log(err);
      }
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"updated"</span>);
    });
</code></pre><p>Call the <code>updateData</code> function to bring everything together:</p>
<pre><code>queryDB(updateData)
</code></pre><h3 id="heading-how-to-test-the-updatedata-file">How to test the <code>updateData</code> file</h3>
<p>Run the command below to see how the <code>updateData</code> function performs:</p>
<pre><code>node updateData
</code></pre><p>It will prompt you for an ID. Enter the ID of any record in the database.  </p>
<p>It will then prompt for updated information about the user. Fill in the information and press <code>Enter</code> for any detail that does not need an update. The terminal should look like this at the end:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675324018105_Screenshot+2023-02-02+at+08.45.07.png" alt="Image" width="1334" height="260" loading="lazy">
<em>updateData Output</em></p>
<p>That wraps it up for the <code>updateData</code> file. Records can now be updated.</p>
<h2 id="heading-how-to-delete-data">How to Delete Data</h2>
<p>A CRUD application cannot be completed without the DELETE part. That will be the focus here. It will borrow a bit from the previous sections. So it will not be too much to grasp.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/JptWEtAtOeA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>You'll begin by typing the following code in the <code>removeData.js</code> file:</p>
<pre><code><span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;
<span class="hljs-keyword">import</span> dbFileCheck <span class="hljs-keyword">from</span> <span class="hljs-string">"./dbFileCheck.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removeData</span>(<span class="hljs-params">info</span>) </span>{
  dbFileCheck();

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"recordID"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Enter Record ID"</span>,
      },
    ]);

    <span class="hljs-keyword">let</span> remnantData = [];
    info.forEach(<span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (element.id !== answers.recordID) {
        remnantData.push(element);
      }
    });

    fs.writeFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(remnantData), <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
      <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.log(err);
      }
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Deleted!"</span>);
    });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>First, the code above collects an ID.  </p>
<p>Next, it uses the ID to search the database data and keeps only data with a different ID in the <code>remnantData</code> array.  </p>
<p>Finally, it overwrites the database with the updated data.  </p>
<p>Call the removeData function at the bottom to put everything together like this:</p>
<pre><code>queryDB(removeData)
</code></pre><p>Now try to test the file using this command:</p>
<pre><code>node removeData
</code></pre><p>The is my output:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675329363353_Screenshot+2023-02-02+at+10.15.12.png" alt="Image" width="1309" height="109" loading="lazy">
<em>removeData Ouput</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The best way to learn to program is by building. And some of the best projects to build are CRUD applications because they cover the basics of what a professional project requires. That is what I have done in this tutorial.  </p>
<p>I have taught you the basics of Nodejs by building an application that creates, reads, updates, and deletes records. I covered concepts such as reading files, writing to files, loops, conditional statements, modules, and CLI operations.  </p>
<p>All the files for this tutorial are on <a target="_blank" href="https://github.com/EBEREGIT/Nodejs_CLI_app">GitHub</a>.  </p>
<p>You now have all the basics needed to start building applications using Nodejs. Something I will like you to try is to update or delete more than one record at a time.</p>
<p>I have some other tutorials on Nodejs, and I suggest that you follow them in this order to grow your skill:</p>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/build-a-secure-server-with-node-and-express/">How to Build a Secure Server with Node.js and Express and Upload Images with Cloudinary</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-backend-application/">How to Build and Deploy a Backend App with Express, Postgres, Github, and Heroku</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-fullstack-authentication-system-with-react-express-mongodb-heroku-and-netlify/">How to Build a Full-Stack Authentication App With React, Express, MongoDB, Heroku, and Netlify</a></li>
</ul>
<p>Happy Building!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ File Permissions in Linux – How to Use the chmod Command ]]>
                </title>
                <description>
                    <![CDATA[ Just as with other operating systems, multiple users can create user accounts and share the same machine running Linux OS.  But whenever different users share a system, problems of privacy can easily arise. The first user may not wish the next user t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/file-permissions-in-linux-chmod-command-explained/</link>
                <guid isPermaLink="false">66ba10a9c003a1736007f4b1</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Mon, 02 Jan 2023 22:17:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/12/Banner---File-permission-blog-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Just as with other operating systems, multiple users can create user accounts and share the same machine running Linux OS. </p>
<p>But whenever different users share a system, problems of privacy can easily arise. The first user may not wish the next user to view, edit, or delete their files, for example.</p>
<p>The Linux Terminal possesses some superpowers when it comes to handling file permissions. You can grant or revoke permissions for every file and directory from your Linux Terminal.</p>
<h2 id="heading-what-are-file-permissions-in-linux">What are File Permissions in Linux?</h2>
<p>File permissions control which actions can be performed by which users. Read, Write, and Execute are the three actions possible for every file. </p>
<p>Users are classified under three broad categories: Normal users, Groups, and Others. Linux allows users to set permissions at a very granular level. You can secure your file or directory in every possible location of a file system. </p>
<p>This seems useful, right?</p>
<p>There are three important commands you'll use when managing file permissions:</p>
<ol>
<li><code>chmod</code> (Change mode)</li>
<li><code>chown</code> (Change ownership)</li>
<li><code>chgrp</code> (Change group)</li>
</ol>
<p>Among these, <code>chmod</code> is one of the most important commands. We'll discuss the <code>chmod</code> command in this tutorial, and I'll get into the others in upcoming articles. </p>
<p>Let’s deep dive into the <code>chmod</code> command 🏊.</p>
<h3 id="heading-actions-you-can-perform-on-a-file">Actions you can perform on a file</h3>
<p>Before we proceed further, I want to make sure you're clear about how the Read, Write, and Execute actions of a file work. Read and write are pretty are self-explanatory – they determine whether a user can read or write to a file.</p>
<p>But, what’s an executable file?</p>
<p>A file is said to be executable if it has a sequence of instructions to achieve something. A good example is scripting files (Shell Scripts). </p>
<h2 id="heading-what-is-the-chmod-command">What is the <code>chmod</code> Command?</h2>
<p><code>chmod</code> is a command that lets you change the permissions of a file or directory to all types of users.</p>
<p>Here’s the syntax of the chmod command:</p>
<pre><code class="lang-bash">chmod &lt;Operations&gt; &lt;File/Directory Name&gt;
</code></pre>
<p>You can grant or revoke the permission by replacing the Operations in the above command.</p>
<h3 id="heading-what-are-the-operations-you-can-perform">What are the operations you can perform?</h3>
<p>The Operations in the above syntax are divided into 2 categories. Let's explore them below.</p>
<h4 id="heading-user-level-permissions">User Level permissions</h4>
<p>These operations control permissions on the user level. Here's the commands you can use:</p>
<ul>
<li><code>u</code> – Grant permission to a user</li>
<li><code>g</code> – Grant permission to a group (A Group of users)</li>
<li><code>o</code> – Grant permission to others (who do not come under either of the above).</li>
</ul>
<p><strong>Note:</strong> If this option is left empty, permissions will be applied to the logged-in user. Most of the time it'll be left empty.</p>
<h4 id="heading-file-level-permissions">File Level permissions</h4>
<p>These control permissions on the file level.</p>
<ul>
<li><code>r</code> – Grants read permission</li>
<li><code>w</code> – Grant write permission</li>
<li><code>x</code> – Grant execute permission</li>
</ul>
<p>These operations need to be preceded with a '+' or '-' operator.</p>
<p>'+' indicates adding a new permission, and '-'  indicates removing an existing permission.</p>
<p>Here's an example:</p>
<pre><code class="lang-bash">chmod +r sample.txt
</code></pre>
<p>The above command adds read permission for the <code>sample.txt</code> file.</p>
<p>Pretty straightforward, right? Let's continue.</p>
<h2 id="heading-how-to-make-a-file-executable-in-linux">How to Make a File Executable in Linux</h2>
<p>I can explain this more clearly with an example from my experience. </p>
<p>Linux is the default operating system of my team. We recently hired an intern, who has zero knowledge of Linux but was curious to learn and explore. We started to train him initially by asking him to write some shell scripts, because most servers run Linux OS. He found the entire code on the internet and copied it (we gave such a task intentionally).</p>
<p>He saved the file but was not able to run the script. He didn't know the actual problem. He started removing a few blocks of code and tried to run it again and again.</p>
<p>He repeatedly got the error stating "Command not found".</p>
<p>Finally, he reached the 1st line. He replaced that line with a print statement (the "echo" command) and ran the file with the hope to see the output. But he still hadn't found that error.</p>
<p>With some frustration, he asked for help.</p>
<p>Let's see the issue now.</p>
<p>Basically, we can execute .sh files by just running them like this:</p>
<pre><code class="lang-bash">./install.sh
</code></pre>
<p>Let's see the code inside <code>install.sh</code></p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"This is executable file 🎉"</span>
</code></pre>
<p>He ran the same command but it did not work. This is because the file was not in executable format. So I ran the magic command to make the file executable:</p>
<pre><code class="lang-bash">chmod +x install.sh
</code></pre>
<p><img src="https://lh3.googleusercontent.com/trd4dTKoxhk9Ap9xLifsuo6bD9wj4kc_i5gtDudFLQyU1gNdJLGoLoyCuJLh1FF9Yah-IG43YuR3yrrtJq48xBEYEq0QQkHMFB1n1YBiv-_fWJT95gyihZD0tjAj0ScnEmF33WRFdHJbfzTSpxSnaimyUbHlK9a2hMujE8CeyT4AoliZY5XJ_wKOsIVrPw" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal command to make a file executable</em></p>
<p>Now it is executable. He stared at me as if I was a hacker 😂. But really, it's a pretty simple and basic concept.</p>
<h2 id="heading-how-to-remove-permissions-from-a-file-in-linux">How to Remove Permissions from a File in Linux</h2>
<p>I work with my colleague Divad on lots of projects, and he likes to try to fool me. We work together on many hobby projects and we often write shell scripts for quick deployment. </p>
<p>Whenever he writes shell scripts, he always removes all the permissions from the file and pushes the changes to the remote repo. So every time I have to grant permissions using the above commands for whatever action I have to do.</p>
<p>Let's have a quick look at the command he uses to remove file permissions.</p>
<p>Here we have a file named <code>install.sh</code> which has all permissions (Read, Write, Execute). Let's remove the execute permission for this script file.</p>
<pre><code class="lang-bash">chmod -x install.sh
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-136.png" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal command to remove execute permission from a file</em></p>
<p>You'll not be able to execute this file now. Trying so will give you an error as shown in the above screenshot.</p>
<p>Let's remove the read permission from the file.</p>
<pre><code class="lang-bash">chmod -r install.sh
</code></pre>
<p>Alright, with this command we've removed the read permission. Let's try to read that file using Nano (the file editor for the Linux terminal). You will be able to see the "Permission Denied" error at the bottom.</p>
<p><img src="https://lh4.googleusercontent.com/DHdaIMmV0pcFiMO-9GiLwXbUes8QZs5v6uKDLfuCu9Ltt-0SitENOM8najXPaxMXFJSQAzlI7F1u1p8i6fbqq1timsCoVGVOBdEtzUlybcmoh0W6oHWrIKyUUJr1dOjDZ_vbo0WkGE3fcLa3T7ZfvymVKVZPoKvKrDDH7ZVFSSlyeyQ1ypLixkAdD5uroA" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://lh3.googleusercontent.com/iphPcFoH9r0VnGArokWKexbVTzGtMkaOC-EgeXECKqHyE2QJMA49sh5HK_u_ZNKDDKc_hmFPe-dM8VVy0Xu-EKGT1VpBaABcUtPxCEipSvNVhwJQWfxisGBHJbvAcosK3kO8JNsWT9qSl2-7A0cK-A8gHjWIK4cfvNAx4iofZOOPOgevXbR8mVjmDZqk0w" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The same applies to removing write permission from the file:</p>
<pre><code class="lang-bash">chmod -w install.sh
</code></pre>
<p><img src="https://lh5.googleusercontent.com/wVL6XdsMVVBrqw3dnrjELCIsqQyDkxtQWUKcD8HyXAUJktcBQyYAK1Ln-A9P517WW1b8tfm95HGd4NmRuP9fgs9QI6w9ZrR0ZeSNyMpWIlYlGld_Vq1-_m8fDDcV9Et-BJd99Jy3RI2cs6vm26Ywp9IFJzx1su8CGVgoe38-BNJp9qDooZe7XAbqv1S88A" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can achieve all the above together using the below command:</p>
<pre><code class="lang-bash">chmod -rwx install.sh
</code></pre>
<p>This is the core part of handling file permissions in Linux. Remember that we have barely scratched the surface of it, though. Try to understand it and play around with some sample files. Because who knows – in the future, you may get a colleague like Divad. :)</p>
<h2 id="heading-how-to-add-or-remove-permissions-for-directories-folders-in-linux">How to Add or Remove Permissions for Directories (Folders) in Linux</h2>
<p>If you work with Linux, you might have come across various directories such as <code>/etc</code>, <code>/var</code>, <code>/opt</code>, and others. But you may not be aware of why these directories exist. </p>
<p>There's one thing in common for all these folders, though: that is, you'll not be able to create a file or folder inside them without root permission.</p>
<p>This setting will be pre-configured in your system when Linux OS is installed.</p>
<p>But, you might wonder, can I restrict my folder in a <code>/home</code> directory similar to the above directories? The answer is yes. You can achieve this by changing the permission of the directory using the <code>chmod</code> command.</p>
<p>Let's understand this with an example.</p>
<p>I created a directory named <code>locked_directory</code> and removed read permission from this directory. If I try to read the contents of the folder using the <code>ls</code> command, I'll end up seeing the "Permission Denied" error message.</p>
<pre><code class="lang-bash">chmod -r locked_directory/
</code></pre>
<p><img src="https://lh5.googleusercontent.com/JfC_fUvfsYzwm23cEaE6ThbFRGdY-tazuXBYIxBdunGsSSema2yGIFkJrLtw0rksPpG4iSUiBqjm9Uu5bEIuTasDyNm_zX0kLAqA3Ncv30FHcmSaXe_XbOzBdIBtg4hVI9kuIwPnRIYhdBZpsfXIaPPnVGUwBP5cwvfWpFn2OPjQfjjiIkkd3rrz0w465A" alt="Image" width="600" height="400" loading="lazy">
<em><code>chmod</code> command to remove read permission from a directory</em></p>
<p>But, did you know that I can create another directory inside <code>locked_directory</code> named <code>dir1</code> and read the files and folders in <code>dir1</code>?</p>
<p><img src="https://lh6.googleusercontent.com/FMLRcjtvY-M1YVSANwmgdzdDwBJ9lrv4V7dLREva9RRUmal7PG8Q5p-l4XZMCi3zIznvSqIKpr68PwGlcripbREffgPzpmqOJ09OR-CvBEGrncBxYX9c9OTe0kq5-xL9rsGP1xQDO_sZP9iXPmHKpXFukFhTIYlXaFRnoHvdCRYA1FJDHcvXmFqP8dmshA" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Then what's the purpose of the command we just ran before? Removing the read permission on the parent should remove the same on child directories too, right?</p>
<p>Well. That's the exact thing I told you earlier. Linux manages a very granular level of file permissions.</p>
<p>If you want to apply the permissions to the parent directory and all its child directories, you need to pass an exclusive flag with the <code>chmod</code> command.</p>
<p>That flag is <code>-R</code>. It basically means applying the same permissions recursively to all sub-directories (child directories). So this permission will apply to the end child of a file/directory.</p>
<p>Here's the syntax for that:</p>
<pre><code class="lang-bash">sudo chmod -R &lt;permission&gt; &lt;filename&gt;
</code></pre>
<p>Remember that running the command to do a recursive operation needs root permission. So you need to add <code>sudo</code> at the beginning of this command. Here's what it looks like:</p>
<pre><code class="lang-bash">sudo chmod -R -r locked_directory
</code></pre>
<p><img src="https://lh3.googleusercontent.com/GZGisVgUxcZjYduKGlOaYHUaTRTgI7tf3nNzdpxL8QZvDDYV_PLgwaFipmbfxzDlziG_Gy7f5Gyeibc_E7IhGvEOmReUKUe3t7yYMXZKDsRnXcxivbepHpqww3y2YSLSyjvi83i_c5Z1rgQbc_ku-Bz5hy8lMl8idzg4MtfYtEZymPFTZBNceq9xgH79ZQ" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal Command to remove read permission from a directory Recursively</em></p>
<p>From the above screenshot, you can see that trying to view the child directory files has failed after removing the read permission recursively from the parent directory.</p>
<h2 id="heading-another-way-to-handle-file-permissions-in-linux">Another Way to Handle File Permissions in Linux</h2>
<p>Alternatively, you can use Octal representation to control the file permissions. </p>
<p>We can use numbers to represent file permissions (the method most commonly used to set permissions). When you change permissions using the Octal mode, you represent permissions for each triplet using a number (4, 2, 1, or combination of 4, 2, and 1).</p>
<p>Let's see the syntax for using octal mode:</p>
<pre><code class="lang-bash">chmod &lt;user&gt;&lt;group&gt;&lt;others&gt; install.sh
</code></pre>
<p>Here's an example of octal mode:</p>
<pre><code class="lang-bash">chmod 777 install.sh
</code></pre>
<h3 id="heading-how-can-i-remove-permissions-using-octal-mode">How can I remove permissions using Octal Mode?</h3>
<p>We can use <code>0</code> to remove permissions from a file. Here's an example:</p>
<pre><code class="lang-bash">chmod 000 install.sh
</code></pre>
<table><thead></thead><tbody><tr><td><strong>Access&nbsp;</strong></td><td><strong>Symbolic Mode</strong></td><td><strong>Octal Mode</strong></td></tr><tr><td>Read</td><td>r</td><td>4</td></tr><tr><td>Write</td><td>w</td><td>2</td></tr><tr><td>Execute</td><td>x</td><td>1</td></tr></tbody><tfoot></tfoot></table>

<p>The table shows the Octal code for each file permission:</p>
<table><thead></thead><tbody><tr><td><strong>Access&nbsp;</strong></td><td><strong>Symbolic Mode</strong><br><strong>Eg:</strong>u+rwx,g+rw,o+r</td><td><strong>Octal Mode&nbsp;</strong><br><strong>Eg:</strong>764 ( User, Group, Others )</td></tr><tr><td>User</td><td>u</td><td>&lt;first place&gt;</td></tr><tr><td>Group</td><td>g</td><td>&lt;middle place&gt;</td></tr><tr><td>Others</td><td>o</td><td>&lt;last place&gt;</td></tr></tbody><tfoot></tfoot></table>

<p>You might be confused 😖. Read further to understand clearly.</p>
<p>Let's consider a scenario.</p>
<p>You want to grant read, write, and execute permissions to users and read-only permission for groups and others to the <code>install.sh</code> file.</p>
<p>Let's see how to do that using the above two methods.</p>
<h3 id="heading-how-to-manage-permissions-in-symbolic-mode">How to manage permissions in Symbolic Mode</h3>
<pre><code class="lang-bash">chmod u+rwx,go+r install.sh
</code></pre>
<p>Let's dismantle each part and try to understand them:</p>
<ul>
<li><code>u+rwx</code> represents adding read, write, and execute permissions for users</li>
<li><code>go+r</code> represents adding read permission for groups and others</li>
</ul>
<h3 id="heading-how-to-manage-permissions-in-octal-mode">How to manage permissions in Octal Mode</h3>
<pre><code class="lang-bash"> chmod 744 install.sh
</code></pre>
<p>Let's dismantle each of these numbers and try to understand them:</p>
<ul>
<li>The first number (7) represents permission for a user: 7 = ( 4 (<code>read</code>) +2 (<code>write</code>) +1(<code>execute</code>) )</li>
<li>The second number (4) represents permissions for a group: 4 (<code>read</code>)</li>
<li>The third number (4) represents permissions for others: 4 (<code>read</code>)</li>
</ul>
<h2 id="heading-which-mode-is-best">Which Mode is Best?</h2>
<p>It turns out that symbolic mode is more powerful than octal mode. </p>
<p>The reason is, in the symbolic mode we can mask out the permission bits we want to change. But in octal mode, permission modes are absolute and can't be used to change individual bits.</p>
<h2 id="heading-how-to-find-permissions-of-a-file">How to Find Permissions of a File</h2>
<p> We can find the existing permissions of a file using ls command.</p>
<p>I hope you all know about <code>ls</code> command. Adding the <code>-l</code> flag and file name with the <code>ls</code> command shows some more info about the file, including the permissions. </p>
<pre><code class="lang-bash">ls -l install.sh
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-137.png" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal command to see the existing permission of a file</em></p>
<p>Look at the first part of the output (<code>-rwxrwxrwx</code>) from the above screenshot. Let's explore what it means: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/permissions-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Existing permissions output description</em></p>
<p>The first character indicates the type of input. </p>
<ul>
<li>"-" indicates a file</li>
<li>"d" indicates a directory</li>
<li>"i" indicates a link (a symlink, which is a shortcut to a file/directory)</li>
</ul>
<p>You group the next set of letters, at a maximum of 3 for each group. These groups represents corresponding permissions for user, group, and others. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you have learned about handling basic file and folder permissions.</p>
<p>I hope you enjoyed reading this tutorial. I have one request to all: give it a try on your own with some complicated scenarios like having permutations and combinations of permissions 😂. It'll definitely be helpful in your entire career.</p>
<p>Subscribe to my newsletter by visiting my <a target="_blank" href="https://5minslearn.gogosoon.com/">site</a> and also have a look at the consolidated list of all my blogs.</p>
<p>Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Improve Your Cybersecurity Command Line Skills – Bandit OverTheWire Game Walkthrough ]]>
                </title>
                <description>
                    <![CDATA[ CTFs and Wargames can help people their improve command line and hacking skills.  The Bandit wargame from OverTheWire is aimed at absolute beginners. It is a game you connect to through SSH that will help you will improve your command line skills, yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/improve-you-cybersecurity-command-line-skills-bandit-overthewire-game-walkthrough/</link>
                <guid isPermaLink="false">66b2039308bc664c3c097eb6</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 09 Nov 2022 16:17:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/new.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>CTFs and Wargames can help people their improve command line and hacking skills. </p>
<p>The Bandit wargame from OverTheWire is aimed at absolute beginners. It is a game you connect to through SSH that will help you will improve your command line skills, your linux skills, and you hacker skills.</p>
<p>We just published a course on the freeCodeCamp.org YouTube channel that will provide you with a complete walkthrough of the 34 levels that are part of the Bandit wargame.</p>
<p>Sabyasachi Paul created this tutorial. He has a lot of experience in the field of cybersecurity. Sabyasachi will guide you through the series of security challenges involving the Linux shell, remote connections, and SSH.</p>
<p>Before watching each challenge solution, consider first trying to solve each challenge yourself.</p>
<p>In this command line game, you start at Level 0 and try to “beat” or “finish” it. Finishing a level results in information on how to start the next level. </p>
<p>If you are following along with the game yourself, you may encounter many situations in which you have no idea what you are supposed to do. There are several things you can try when you are unsure how to continue in the game (before watching the solution).</p>
<p>First, if you know a command, but don’t know how to use it, try the manual (man page) by entering <code>man &lt;command&gt;</code>. For example, <code>man ls</code> to learn about the “ls” command. The “man” command also has a manual, try it! When using man, press q to quit (you can also use / and n and N to search).</p>
<p>Second, if there is no man page, the command might be a shell built-in. In that case use the <code>help &lt;X&gt;</code> command. For example, <code>help cd</code>.</p>
<p>You can find instructions for the game here: <a target="_blank" href="https://overthewire.org/wargames/bandit/">https://overthewire.org/wargames/bandit/</a></p>
<p>Watch the full walkthrough on <a target="_blank" href="https://youtu.be/9ReSHQihuZw">the freeCodeCamp.org YouTube channel</a> (2-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/9ReSHQihuZw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Linux Command Line Tutorial – How to Use Common Terminal Commands ]]>
                </title>
                <description>
                    <![CDATA[ An operating system is a set of software layers between you and your computer's hardware.  The operating system (or OS) is a piece of software that controls all other application programs and helps you manage the hardware and software of your compute... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/linux-command-line-tutorial/</link>
                <guid isPermaLink="false">66b906bae4bfcbefb35a6b98</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ terminal ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Destiny Erhabor ]]>
                </dc:creator>
                <pubDate>Tue, 18 Oct 2022 23:33:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/10/pexels-sora-shimazaki-5935794--3-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>An operating system is a set of software layers between you and your computer's hardware. </p>
<p>The operating system (or OS) is a piece of software that controls all other application programs and helps you manage the hardware and software of your computer.</p>
<p>Examples of popular operating systems are Windows, Linux, MacOS, and Android. In this tutorial, we'll focus on the Linux OS.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/USER--1-.png" alt="Image" width="600" height="400" loading="lazy">
<em>operating system diagram</em></p>
<p>You will learn the most frequently used Linux commands and operators. You'll also get a high level grasp of the Linux operating system and its various distributions, which are referred to as "distros" in this article.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-why-learn-the-linux-command-line">Why learn the Linux command line?</a></li>
<li><a class="post-section-overview" href="#heading-history-of-operating-systems">History of operating systems</a></li>
<li><a class="post-section-overview" href="#heading-the-rise-of-the-gnu-project">The rise of the GNU Project</a></li>
<li><a class="post-section-overview" href="#heading-how-linux-works-and-its-basic-components">How Linux works and its basic components</a></li>
<li><a class="post-section-overview" href="#heading-what-are-linux-distributions">What are Linux distributions?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-choose-a-linux-distribution">How to choose a Linux distribution</a></li>
<li><a class="post-section-overview" href="#heading-basic-linux-commands-to-run-in-the-terminal">Basic Linux commands to run in the terminal</a></li>
<li><a class="post-section-overview" href="#heading-how-to-work-with-directories-in-linux">How to work with directories in Linux</a></li>
<li><a class="post-section-overview" href="#heading-commands-to-work-with-files-in-linux">Commands to work with files in Linux</a></li>
<li><a class="post-section-overview" href="#heading-commands-to-work-with-file-contents">Commands to work with file contents</a></li>
<li><a class="post-section-overview" href="#heading-linux-command-operations">Linux command operations</a></li>
</ul>
<h2 id="heading-why-learn-the-linux-command-line">Why Learn the Linux Command Line?</h2>
<p>There are lot of reason why you should learn about the Linux command line. Some of these are:</p>
<ul>
<li><strong>More Control Over Your Machine</strong>: You have a great deal of power and control with the command line. You can run commands to change permissions, view hidden files, interact with databases, start servers, and more.</li>
<li><strong>It's Faster</strong>: You can complete tasks much more quickly with the basic commands in your toolbox than you could with a Graphical User Interface (GUI). Just keep in mind that it might be slower while learning the CLI.</li>
<li><strong>Automate Many Tasks</strong>: You may speed up your work by using a single command to create 10,000 files, each with a unique name. With a GUI, this process is laborious.</li>
<li><strong>Available Everywhere</strong>: The instructions you issue will automatically run similarly on Linux and Mac computers. And with a little tweaking, they will also function on Windows.</li>
<li><strong>Basic requirement</strong>: You NEED to use the command line if you want to advance your knowledge in any coding-related technology field, including development, data analysis, devops engineering, system administration, security, machine learning engineering, and others.</li>
</ul>
<h2 id="heading-history-of-operating-systems">History of Operating Systems</h2>
<p>Most OSs are generally divided into two families: Unix-based and Microsoft NT descendants.</p>
<p><strong>Unix</strong> was an OS developed in the mid 1960s. It's the "grandparent" of many modern operating system that we frequently use now, such as Linux. </p>
<p>The Unix operating system was a closed source project (meaning its code and files weren't made public). And this led to the rise of the "Free software" movement led by Richard Stallman. It argued that users should have the freedom to run, copy, distribute, and collaborate on the source code of a project.</p>
<p><strong>Microsoft NT descendants</strong> were proprietary graphical operating systems that Microsoft created. The Windows NT descendants don't natively have similar Linux commands, unlike Unix and Unix-based Operating Systems, which do. Instead, Microsoft NT has its own set of commands and default shells. </p>
<p>Microsoft NT's offspring includes Windows, Xbox OS, Windows Phone/Mobile, and others.</p>
<h2 id="heading-the-rise-of-the-gnu-project">The Rise of the GNU Project</h2>
<p>Richard Stallman wanted to create a free software alternative to Unix. He worked with some other developers in 1984 to create a full operating system that would be free. So they started working on the GNU project. </p>
<p>At same time, another developer called Linus Torvalds was creating his own kernel known as Linux. At that time, many GNU pieces were completed but they lacked a kernel. Torvalds combined his kernel with the existing GNU components to create a full OS. </p>
<p>Some developers strongly feel that the name should be GNU/Linux instead of just Linux, as it reflects the joining of the Linux kernel with the GNU project.</p>
<h2 id="heading-how-linux-works-and-ihttpsenwikipediaorgwikigraphicaluserinterfacets-basihttpsenwikipediaorgwikigraphicaluserinterfacec-components">How Linux Works and <a target="_blank" href="https://en.wikipedia.org/wiki/Graphical_user_interface">i</a>ts Bas<a target="_blank" href="https://en.wikipedia.org/wiki/Graphical_user_interface">i</a>c Components</h2>
<p>In this section, you will learn how Linux works by understanding its fundamental components. We'll now discuss these elements.</p>
<h3 id="heading-what-is-a-kernel">What is a kernel?</h3>
<p>A <strong>kernel</strong> is a part of an OS that facilitates interactions between the hardware and software. It's an essential element of an operating system for a computer.</p>
<p>The core of the OS alone is responsible for providing all other components with necessary services. It helps with device control, networking, file system management, process and memory management, and it acts as the main interface between the OS and the hardware.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-11-1.png" alt="Image" width="600" height="400" loading="lazy">
<em><a target="_blank" href="https://d1m75rqqgidzqn.cloudfront.net/wp-data/2022/08/04135248/image-11.png">kernel</a></em></p>
<h3 id="heading-what-is-a-shell">What is a Shell?</h3>
<p>A shell is a computer interface to an operating system. The shell exposes the services of the OS to users or other programs. The shell takes your commands and gives them to the OS so it can perform them. </p>
<p>It's named a shell because its the outer layer around the OS – like the shell around an oyster!</p>
<h3 id="heading-what-is-the-terminal">What is the Terminal?</h3>
<p>A terminal is a program that runs a shell. This is where we run most of our commands that tell the OS what to do. </p>
<p>You install the terminal in the following ways on different operating systems:</p>
<ul>
<li><strong>Linux Distro users</strong> – the Bash shell is installed by default</li>
<li><strong>Mac Users</strong> – Terminal is installed by default and can execute similar Linux commands</li>
<li><strong>Windows Users</strong> – Download <a target="_blank" href="https://www.freecodecamp.org/news/how-to-install-wsl2-windows-subsystem-for-linux-2-on-windows-10/">Windows Subsystem for Linux (WSL)</a> or use <code>git bash</code> and run all Linux command from there.</li>
</ul>
<h2 id="heading-what-are-linux-distributions">What are Linux Distributions?</h2>
<p>Linux distributions (popularly called <strong>distros)</strong> are flavors of the Linux operating system. These distros are built based on Linux's open source software. </p>
<p>Some examples of these are:</p>
<h3 id="heading-debian-family">Debian Family</h3>
<p>Since it was founded in 1993, Debian has released new versions far more slowly than Ubuntu and mint. It is one of the most reliable Linux distributors as a result.</p>
<p>Debian is the foundation of Ubuntu, which was created to expeditiously enhance Debian's fundamental components and make it more user-friendly.</p>
<p>Ubuntu was created by Canonical in 2004 and gained popularity immediately. Canonical wants Ubuntu to be used as a simple, command-line-free graphical Linux desktop. It's the most well-known Linux distribution. </p>
<p>Ubuntu is simple for beginners to use. It has a large number of pre-installed applications and convenient repository libraries.</p>
<h3 id="heading-red-hat-family">Red Hat Family</h3>
<p>Red Hat is a professional Linux distributor. Red Hat Enterprise Linux (RHEL) and Fedora are their products, both of which are open source. </p>
<p>Fedora offers faster updates and no support, but RHEL is thoroughly tested before release and supported for seven years after the release.</p>
<p>Red Hat uses trademark law to stop the redistribution of its software. Red Hat Enterprise Linux source is used in CentOS, a community effort that eliminates all of Red Hat's trademarks and makes it publicly available. In other words, it is a free version of RHEL and offers a long-lasting reliable platform.</p>
<h3 id="heading-suse-family">SUSE Family</h3>
<p>SUSE created its own operating system for computers. It is supplied with system and application software from other open source projects and is developed on top of the free and open source Linux kernel. </p>
<p>SUSE Linux was primarily developed in Europe and is of German origin. The name SUSE is an acronym for "Software und System-Entwicklung." SUSE is one of the oldest commercial distributions still in use because the initial version debuted in early 1994.</p>
<h3 id="heading-fedora-family">Fedora Family</h3>
<p>This is a project that offers the most recent software versions and mostly focuses on free software. It uses 'upstream' applications instead of developing its own desktop environment. It comes with the GNOME3 desktop environment by default. Although less reliable, it offers the newest information.</p>
<h2 id="heading-how-to-choose-a-linux-distribution">How to Choose a Linux Distribution</h2>
<table><tbody><tr><th>Distribution</th><th>Reason To Use</th></tr><tr><td>Ubuntu</td><td>It works like Mac OS and easy to use.</td></tr><tr><td>CentOS</td><td>If you want to use red hat but without its trademark.</td></tr><tr><td>Fedora</td><td>If you want to use red hat and latest software.</td></tr><tr><td>Red hat enterprise</td><td>Used commercially.</td></tr><tr><td>OpenSUSE</td><td>It works same as Fedora but slightly older and more stable.</td></tr><tr><td>Arch Linux</td><td>It is not beginner friendly.</td></tr></tbody></table>

<p>Now let's talk about some commands you can run to interact with the shell.</p>
<h1 id="heading-basic-linux-commands-to-run-in-the-terminal">Basic Linux Commands to Run in the Terminal</h1>
<h3 id="heading-the-whoami-command">The <code>whoami</code> command</h3>
<p>This command prints the name of the currently logged in user to the terminal session.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ whoami
</code></pre>
<h3 id="heading-the-man-command">The <code>man</code> command</h3>
<p>This command prints the <strong>manual</strong> or information about a command, configuration files, and so on. This command is very useful when it comes to getting more information about any command.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ man whoami
</code></pre>
<h3 id="heading-the-clear-command">The <code>clear</code> command</h3>
<p>Clears all previous commands that were run in the current terminal. This clears the screen from previous commands in the terminal.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ clear
</code></pre>
<h3 id="heading-how-to-open-files">How to open files</h3>
<h4 id="heading-mac-users">Mac Users:</h4>
<p><code>open &lt;filename or directory name&gt;</code></p>
<p>The open command lets you open a file or directory in the graphical user interface (GUI) outside the terminal.</p>
<h4 id="heading-linux-users">Linux Users</h4>
<p><code>xdg-open &lt;filename or directory name"</code></p>
<h4 id="heading-windows-wsl-users">Windows WSL users</h4>
<p>You can open files in a similar way to Linux, but you need to install the xdg-open package.</p>
<p>Example for Linux and Windows users:</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ xdg-open clean-code-architecture.pdf
</code></pre>
<p>Now that we have covered the basic commands, let's learn a few other commands you'll use a lot.</p>
<h2 id="heading-how-to-work-with-directories-in-linux">How to Work with Directories in Linux</h2>
<p>Now let's see some of the most common commands you'll use to work with directories. </p>
<p>Directories are like folders, and you can create, delete, and perform all functions on them through your system interface with a mouse or cursor.</p>
<p>Here we will be doing something similar but from the comfort of our terminal. The following commands let you perform different operations on directories:</p>
<ul>
<li><strong><code>pwd</code></strong> (present working directory)</li>
<li><strong><code>cd</code></strong> (current directory)</li>
<li><strong><code>ls</code></strong> (list)</li>
<li><strong><code>mkdir</code></strong> (make directory)</li>
<li><strong><code>rmdir</code></strong> (remove directory)</li>
</ul>
<p>Let's look at what each one does:</p>
<h3 id="heading-the-pwd-command">The <code>pwd</code> command</h3>
<p>Whenever you feel lost in the filesystem, call the <code>pwd</code> command to know where you are. It takes no argument.</p>
<pre><code class="lang-bash">casesarsage@caesarsage:~/Documents/github.com$ <span class="hljs-built_in">pwd</span>
</code></pre>
<p>It should print the current folder/directory path where you currently are.</p>
<h3 id="heading-the-cd-command">The <code>cd &lt;path&gt;</code> command</h3>
<p>You can change your current directory with the cd command (Change Directory). Just like going back and forth between folders when using the GUI.</p>
<pre><code class="lang-bash">caesarsage@caesarsage$: <span class="hljs-built_in">cd</span> Documents/articles
</code></pre>
<p>This command takes me to a folder called articles inside my Documents folder.</p>
<p>Let's see what else you can do with <code>cd</code>.</p>
<h4 id="heading-cd"><code>cd ~</code></h4>
<p>The cd is also a shortcut to get back into your home directory. Just typing cd without a target directory will put you in your home directory. Typing <code>cd ~</code> has the same effect.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~/Documents/github.com$ <span class="hljs-built_in">cd</span> ~
</code></pre>
<p>This takes your to you home directory from the github.com folder</p>
<h4 id="heading-cd-1"><code>cd ..</code></h4>
<p>To go to the parent directory (the one just above your current directory in the directory tree), type <strong><code>cd ..</code></strong>:</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~/Documents/github.com$ <span class="hljs-built_in">cd</span> ..
</code></pre>
<h3 id="heading-the-ls-command">The <code>ls</code> command</h3>
<p>Inside a folder you can list all the files that the folder contains using the <code>ls</code> command. It takes no arguments.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~/Documents/mycatfolder$ ls
</code></pre>
<p>Just like with <code>cd</code>, there are some other options you can use with <code>ls</code>:</p>
<h4 id="heading-ls-a"><code>ls -a</code></h4>
<p>A frequently used option with ls is -a to show all files. Showing all files means including the hidden files. </p>
<p>When a file name on a Linux file system starts with a dot, it is considered a hidden file and it doesn't show up in regular file listings. This command will show those files.</p>
<h4 id="heading-ls-l"><code>ls -l</code></h4>
<p>Many times you will be using options with ls to display the contents of the directory in different formats or to display different parts of the directory. </p>
<p>Typing just ls gives you a list of files in the directory. Typing <strong><code>ls -l</code></strong> gives a long listing and permission as (<strong>rwx</strong> - read, write, execute).</p>
<h3 id="heading-the-mkdir-command">The <code>mkdir &lt;directoryName&gt;</code> command</h3>
<p>Walking around the Unix file tree is fun, but it is even more fun to create your own directories/folders with <strong>mkdir</strong>. </p>
<p>You have to give at least one parameter to <code>mkdir</code> – the name of the new directory to be created. Think before you type a leading / .</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~/Documents$ mkdir cats
</code></pre>
<h3 id="heading-the-rmdir-command">The <code>rmdir &lt;directoryName&gt;</code> command</h3>
<p>When a directory is empty, you can use <strong>rmdir</strong> to remove or delete the directory.</p>
<pre><code class="lang-bash">caesarsage@caesarsage~/Documents$ rmdir cats
</code></pre>
<h4 id="heading-rmdir-p"><code>rmdir -p &lt;directoryName&gt;</code></h4>
<p>When you want to delete nested directories, you can used the <strong>-p</strong> flag. You use <code>rmdir -p</code> to recursively remove directories. This is similar to creating nested directories with <strong>mkdir -p</strong>.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~/Documents$ rmdir -p articles/drafts
</code></pre>
<h2 id="heading-commands-to-work-with-files-in-linux">Commands to Work with Files in Linux</h2>
<p>In this section, you'll learn how to recognize, create, remove, copy, and move files using the following commands:</p>
<ul>
<li><strong><code>touch</code></strong></li>
<li><strong><code>rm</code></strong></li>
<li><strong><code>cp</code></strong></li>
<li><strong><code>mv</code></strong></li>
<li><strong><code>rename</code></strong></li>
</ul>
<h3 id="heading-the-touch-command">The <code>touch &lt;filename&gt;</code> command</h3>
<p>One easy way to create an empty file is with <code>touch</code> like this:</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~$ touch file1.txt file2.md file3
</code></pre>
<p>The above creates three files (text and markdown files).</p>
<h3 id="heading-the-rm-command">The <code>rm &lt;filename&gt;</code> command</h3>
<p>When you no longer need a file, use rm to remove it. </p>
<p><strong>Note</strong> that unlike some graphical user interfaces, the command line in general does not have a waste bin or trash from where you can recover files. When you use <code>rm</code> to remove a file, the file is gone. So be careful when removing files!</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~$ rm file1.txt
</code></pre>
<p>Here are some more specific ways to use <code>rm</code>:</p>
<h4 id="heading-rm-v"><code>rm -v &lt;filename&gt;</code></h4>
<p>This flags gives you feedback of what it did (deleting a file).</p>
<h4 id="heading-rm-i"><code>rm -i &lt;filename&gt;</code></h4>
<p>To prevent yourself from accidentally removing a file, you can type <code>rm -i</code>. This will show a prompt to confirm if you really want to delete the file or not.</p>
<h4 id="heading-rm-rf-or"><code>rm -rf &lt;filename&gt;or&lt;directory&gt;</code></h4>
<p>By default, <code>rm -r</code> will not remove non-empty directories. However rm accepts several options that will allow you to remove any directory. </p>
<p>The <code>rm -rf</code> statement is famous because it will erase anything (providing that you have the permissions to do so). When you are logged in as root, be very careful with <code>rm -rf</code> (the f means force and the r means recursive), since being root implies that permissions don't apply to you. You can literally erase your entire file system by accident.</p>
<h3 id="heading-the-cp-command">The <code>cp &lt;fileold&gt; &lt;newfile&gt;</code> command</h3>
<p>To copy a file, use <code>cp</code> with a file name and a new file name argument.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ cp text2.md text2Copy.md
</code></pre>
<h4 id="heading-cp"><code>cp &lt;source&gt; &lt;destination&gt;</code></h4>
<p>Use this option to copy a file to another directory (destination).</p>
<p>If the target is a directory, then the source files are copied to that target directory.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~$ mkdir dir3
caesarsage@caesarsage:~$ cp file2.md dir3
</code></pre>
<h4 id="heading-cp-r-directorysource-dirtarget"><code>cp -r directorySource dirTarget</code></h4>
<p>To copy complete directories, use <code>cp -r</code> (the -r option forces recursive copying of all files in all sub-directories).</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~$ cp -r dir1/dir2  dir3
</code></pre>
<h3 id="heading-the-mv-source-destination-command">The <code>mv source destination</code> command</h3>
<p>You can use the <code>mv</code> command to move and rename directories.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:~/Documents/$ mv cat catFolder
</code></pre>
<pre><code class="lang-bash">caesarsage@caesarsage:~/Documents/$ mv newarticle.txt articles
</code></pre>
<h2 id="heading-commands-to-work-with-file-contents">Commands to Work with File Contents</h2>
<p>You can use the following commands to look at the contents of text files:</p>
<ul>
<li><strong><code>head</code></strong></li>
<li><strong><code>tail</code></strong></li>
<li><strong><code>cat</code></strong></li>
<li><strong><code>less</code></strong></li>
<li><strong><code>echo</code></strong></li>
<li><strong><code>wc</code></strong></li>
<li><strong><code>grep</code></strong></li>
</ul>
<h3 id="heading-the-head-command">The <code>head &lt;file&gt;</code> command</h3>
<p>This command prints the first part of the files. By default it gives the first 10 lines of a file, but you can override that by adding the <code>-n</code> flag.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ head /etc/passwd
</code></pre>
<h3 id="heading-the-tail-command">The <code>tail &lt;file&gt;</code> command</h3>
<p>This command prints the last 10 lines of a file. You can also override the default similarly by passing the <code>-n</code> flag.</p>
<p>The tail file also has an <code>-f</code> flag that helps you keep printing extra additions to a file. This is useful for logs and errors files that keep changing in your system so you can monitor them.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ tail /etc/passwd
</code></pre>
<h3 id="heading-the-cat-command">The <code>cat &lt;filename&gt;</code> command</h3>
<p><code>cat</code> can add content to a file which makes it super powerful. In its simplest usage, cat prints a file's contents to the standard outputs.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ cat file
</code></pre>
<p>You can print the content of multiple files as well.</p>
<p>And using the <strong>operator &gt;</strong> (we will see what this does later – for now, know it takes terminal output into a file) you can concatenate the content of multiple files into a new file:</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ cat file2.txt file3.txt &gt; combine.txt
</code></pre>
<p>You can also use it to create files:</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ cat &gt; newfile.txt
</code></pre>
<h3 id="heading-the-less-command">The <code>less &lt;filename&gt;</code> command</h3>
<p>The <code>less</code> command shows the content stored inside a file in a nice and interactive UI.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ less /etc/passwd
</code></pre>
<p>Use <strong>b</strong> to scroll one page, <strong>G</strong> to the go to end, <strong>g</strong> to go to the start and <strong>q</strong> to quit the cmd.</p>
<h3 id="heading-the-echo-command">The <code>echo</code> command</h3>
<p>This command prints to the output the argument passed to it.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ <span class="hljs-built_in">echo</span> <span class="hljs-string">'Hello world'</span>
</code></pre>
<h3 id="heading-the-wc-command">The <code>wc &lt;input&gt;</code> command</h3>
<p><code>wc</code> stands for word count, and this command gives information about input (for example a file) like number of lines, number of words, number of bytes for content, and so on.</p>
<h4 id="heading-wc-l"><code>wc -l</code></h4>
<p>This option prints only the newline count.</p>
<h4 id="heading-wc-m"><code>wc -m</code></h4>
<p>This option prints only the character count.</p>
<h4 id="heading-wc-c"><code>wc -c</code></h4>
<p>This option prints only the byte count.</p>
<h4 id="heading-wc-w"><code>wc -w</code></h4>
<p>This option prints only the word count.</p>
<h3 id="heading-the-grep-command">The <code>grep</code> command</h3>
<p>The command grep is probably the most widely used text manipulation command. It lets you filter the content of a file for display. </p>
<p>If, for instance, you want to see all lines that include the word output in your file, you could use cat and ask it to display only those lines.</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ cat /etc/snort/snort.conf | grep output
</code></pre>
<p>You will learn more about the pipe (|) operator in the next section.</p>
<h2 id="heading-linux-command-operations">Linux Command Operations</h2>
<p>Some common commands you can use to manipulate Linux commands are:</p>
<ul>
<li><strong><code>&gt;</code></strong>: redirects standard outputs</li>
</ul>
<p>Most of the commands we have seen so far print something out for us on the terminal. For example the PWD prints out our current directory, and so on. </p>
<p>These outputs can be stored and redirected to a file with the use of "&gt;". It overrides the current file contents when you run it multiple times.</p>
<pre><code class="lang-bash">caesarsage@caesarsage: whoami &gt; file.txt
caesarsage@caesarsage: <span class="hljs-built_in">pwd</span> &gt; file.txt
caesarsage@caesarsage: cat &gt; file.txt
</code></pre>
<ul>
<li><strong><code>&gt;&gt;</code></strong>: redirects standard outputs and appends new contents.</li>
</ul>
<p>Unlike the '&gt;' operation, &gt;&gt; doesn't override previously stored output in a file.</p>
<pre><code class="lang-bash">caesarsage@caesarsage: whoami &gt;&gt; file.txt
caesarsage@caesarsage: <span class="hljs-built_in">pwd</span> &gt;&gt; file.txt
caesarsage@caesarsage: cat file.txt
</code></pre>
<ul>
<li><strong><code>|</code></strong>: this operator is called pipe.</li>
</ul>
<p>This takes the output of one command and passes it as the input for another command. Here's how you use it:</p>
<pre><code class="lang-bash">caesarsage@caesarsage:$ cat /etc/snort/snort.conf | grep output
</code></pre>
<h1 id="heading-summary">Summary</h1>
<p>In this article, you learned about the Linux operating system at a high level. You also learn to use the Linux command line to interact with the OS.</p>
<p>As always, I hope you enjoyed the article and learned something new. If you want, you can also follow me on <a target="_blank" href="https://www.linkedin.com/in/destiny-erhabor">LinkedIn</a> or <a target="_blank" href="https://twitter.com/caesar_sage">Twitter</a>.</p>
<p>Cheers and see you in the next one! ✌️</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Command Line Interface – for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ There's a lot to learn when you're getting into tech. But fortunately there are some skills that you can use across different programming languages, operating systems, and tools.  And knowing how to use the command line interface (also known as the c... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-cli-beginner-guide/</link>
                <guid isPermaLink="false">66c71fdc99aed080e9571bc4</guid>
                
                    <category>
                        <![CDATA[ beginners guide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mabel Obadoni ]]>
                </dc:creator>
                <pubDate>Tue, 27 Sep 2022 21:11:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/BEGINNERS--HACK-ON-USING-CLI--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There's a lot to learn when you're getting into tech. But fortunately there are some skills that you can use across different programming languages, operating systems, and tools. </p>
<p>And knowing how to use the command line interface (also known as the command prompt or terminal, depending on your operating system) is one of those skills.</p>
<p>Whether you're doing Web development, Game Development, Application Development, Cloud Engineering, DevOps, or many other disciplines in tech, you'll likely use the command line quite often.</p>
<h2 id="heading-history-of-the-command-line">History of the Command Line</h2>
<p>In the early days of computers, developers used MS-DOS to navigate around the computer system.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-390.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Disk Operating System (<strong>DOS</strong>) is a kind of operating system that uses commands (words) to interact with the computer. </p>
<p>The DOS didn’t use mouse pointers, icons, or any graphics, so users were stuck with using text-commands to operate the computer system.</p>
<p>For instance, to go to a particular folder, you'd type:</p>
<p><code>Cd &lt;name of folder&gt;</code></p>
<p>The command line interface (or CLI for short) is similar to DOS in that it uses commands to perform various operations, like creating files, creating folders, installing programs, and what have you.</p>
<p>The advancement of technology over the years brought about the popular GUI (Graphical User Interface) and made Operating Systems less stressful to use.</p>
<p>Although developers (and non-technical users) often use the GUI these days, sometimes working directly from the CLI is useful or necessary, irrespective of your stack.</p>
<h2 id="heading-what-is-the-cli-is-it-a-programming-language">What is the CLI? Is it a Programming Language?</h2>
<p><img src="https://images.unsplash.com/photo-1646406694751-9df2f91f1161?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDMwfHxjb25mdXNlZCUyMGRldmVsb3BlcnxlbnwwfHx8fDE2NjM1ODgzMzA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="A portrait of a girl with a cute expression." width="2000" height="3000" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@angshu_purkait?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Angshu Purkait / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>If you're new to software development, it's easy to get carried away with the various terminology you'll need to learn. Worry less, you are not doing a spelling bee competition. Rather, you are meant to learn what these terms refer to, how they actually work, and how you can use them. </p>
<p>One of the terms you'll hear quite often is the Command Line Interface (also referred to as Command Prompt or Terminal).</p>
<p>The Command Line Interface (CLI) is an editing environment that is text-based. It uses specified text (known as commands) to interact with the computer and perform numerous operations, including installing and working with programs.</p>
<p>Every operating system comes with an inbuilt command prompt. Some application packages such as Nodejs, Anaconda, Git, and so on also come with their own command prompt. </p>
<p>The same thing goes for Cloud Providers such as AWS, GCP, Azure. Although the CLI bears different names across different platforms or packages, its purpose remains the same: to let you interact freely with the software package or the computer system using text-based instructions known as commands.</p>
<p>So, the CLI is a tool, not a programming language.</p>
<p>A basic knowledge of CLI will help you along your tech journey, especially if you are into Software Development. In fact, you can completely build a program and run it right from the CLI. </p>
<p>This article will:</p>
<ul>
<li>Explain how the CLI Works</li>
<li>Help you locate your CLI according to your OS</li>
<li>Show you how to perform basic operations using the CLI</li>
<li>Help you differentiate between the CLI and GUI</li>
</ul>
<h2 id="heading-how-the-cli-works">How the CLI Works</h2>
<p>As briefly discussed earlier, the CLI uses text-based instructions to perform operations. These commands have specific syntax you need to follow and certain text must be written on the same line – otherwise it'll throw an error message. </p>
<p>In the case of CLI in application packages, the commands may be relative to the package in question. But all CLIs follow the same rule of being semantic and on the same line.</p>
<p>To use your CLI:</p>
<ul>
<li>Locate the CLI in your PC</li>
<li>Open it</li>
<li>Type in your desired commands</li>
<li>Press the enter key</li>
</ul>
<p>Later in the tutorial, we'll execute some commands using the CLI so you can better understand how it works.</p>
<h2 id="heading-the-command-line-in-different-operating-systems">The Command Line in Different Operating Systems</h2>
<p>Every Operating System comes with its default Command Line Interface, though you can choose to install a more advanced CLI depending on your needs.</p>
<p>Some Operating Systems and their respective CLIs are listed below:</p>
<ul>
<li>Windows: Command Prompt</li>
<li>Linux: Linux Bash Shell</li>
<li>MacOs: Mac Terminal</li>
<li>Google Cloud Platform: PowerShell, Cloud shell</li>
<li>Amazon Web Services: AWS Command Prompt</li>
<li>Microsoft Azure: Azure CLI bash</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/BEGINNERS--HACK-ON-USING-CLI--2-.png" alt="Image" width="600" height="400" loading="lazy">
<em>A picture of Windows command prompt, AWS Cloudshell, MacOs Terminal and Linux Terminal</em></p>
<p>I currently use Windows OS and Windows Command Prompt, but I'll also show you how you can locate your own Terminal or Command Prompt based on popular Operating systems.</p>
<h2 id="heading-how-to-locate-your-cli">How to Locate your CLI</h2>
<h3 id="heading-in-windows">In Windows</h3>
<p>You can access the command prompt in Windows OS using the program directory or using shortcut keys.</p>
<p>Using the program directory, go to your search bar (next to the Windows icon) and type <strong>cmd.</strong> This will pop up a list of all the command prompts available on your machine, including the default windows cmd. You can now select the one you wish.</p>
<p>Using a keyboard shortcut, press <strong>Windows + R</strong> on your keyboard and type in <strong>cmd</strong> on the dialog box that pops up.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/CMD-1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>A picture showing the run terminal</em></p>
<h3 id="heading-in-macos">In MacOS</h3>
<p>As in the case of Windows, you can also open the CLI in a Mac OS using the program directory or a keyboard shortcut.</p>
<p>To use the program directory, locate the launchpad and type in <strong>Terminal</strong>. This will bring it up.</p>
<p>To use the keyboard shortcut, type the combination of the <strong>cmd</strong> + <strong>space bar</strong> keys.</p>
<p>Here's how to locate MacOs Terminal and create a file in a directory:</p>
<div class="embed-wrapper">
        <iframe width="640" height="360" src="https://player.vimeo.com/video/754058144" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="Vimeo embed" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-perform-basic-operations-using-the-cli">How to Perform Basic Operations Using the CLI</h2>
<p>Back in Mathematics class, it was quite easy to memorize formulas and solve equations using those memorized formulas. But knowing when to apply those equations in real life scenarios was – and often continues to be – difficult for many students.</p>
<p>Knowing where your CLI is located and how it works is a good step in the right direction. But let me show you how to get started with the CLI by practicing simple operations right from your Command Prompt.</p>
<h3 id="heading-how-to-navigate-through-your-pc-with-the-cli">How to navigate through your PC with the CLI</h3>
<p>Navigating through your PC simply means moving from one folder or file to another. If you don't want to use your mouse to direct your cursor, you can move around your PC using the CLI. </p>
<p>For instance in Windows, if you want to open the desktop, take the following steps:</p>
<ol>
<li>Open the CLI (CMD) as explained earlier</li>
<li>Next, type in <strong>cd Desktop</strong> on the command prompt which will take you to your desktop</li>
</ol>
<p>Keep in mind that this command is for Windows OS (for Mac, for example, it'll be slightly different).</p>
<p>Here's what you'll see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/CMD-2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-a-folder-using-the-cli">How to create a folder using the CLI</h3>
<p>You may know the usual method of right-clicking on your screen and selecting the "New folder" option on the drop-down menu. But there's a way of creating a new folder using the CLI.</p>
<ol>
<li>First, open your CLI</li>
<li>Navigate to the folder or location where you want to create the new folder</li>
<li>Enter <strong>mkdir </strong></li>
<li>Press Enter</li>
<li>You can now enter the folder by typing <strong>cd </strong></li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/CMD-3.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-install-a-package-using-the-cli">How to install a package using the CLI</h3>
<p>Installing a software package or application using the CLI depends on the package in question. </p>
<p>Packages like Node.js (a development package for BackEnd Development) require that you install the Node Package Manager (npm). This package manager is what you'll use to install and run Node and other similar packages. </p>
<p>Some commands for installing software packages via the CLI include:</p>
<ol>
<li><code>Install &lt;name of package&gt;</code></li>
<li><code>run &lt;name of package</code></li>
</ol>
<p>For instance to install a new instance of a React app:</p>
<ul>
<li><p>Open the terminal</p>
</li>
<li><p>locate your local environment by typing:</p>
</li>
</ul>
<p><code>cd Desktop</code></p>
<ul>
<li>Create a directory for the app by typing:</li>
</ul>
<p><code>cd Desktop mkdir my_directory</code></p>
<ul>
<li>create the react-app right in the directory by using the command:</li>
</ul>
<p><code>npx create-react-app my-app</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/cmd9.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>A terminal showing the commands for installing create-react-app using Windows Command Prompt</em></p>
<h2 id="heading-differences-between-the-cli-and-gui">Differences Between the CLI and GUI</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/BEGINNERS--HACK-ON-USING-CLI--3-.png" alt="Image" width="600" height="400" loading="lazy">
<em>GUI vs CLI image</em></p>
<p>As we've discussed, the CLI uses commands to generally interact with the computer.</p>
<p>On the other hand, the Graphical User Interface (GUI) is a method of interacting with the computer using icons, menus, mouse clicks, and pointers. </p>
<p>An Operating System that is GUI-based allows users to freely operate the computer by clicking, dragging, dropping, and other visual methods of interacting with the computer.</p>
<p>Unlike the GUI, the CLI uses less RAM space and interacts with the operating system directly.</p>
<p>To use the GUI, no programming knowledge is required. But to use the CLI, you need to have a certain amount of knowledge of programming and command operations.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As you begin or advance in your tech journey, you'd need to install a lot of programs that are foreign to your Local Machine. Such programs may not have GUI installation methods and may require you to run a line of code or more on your CLI. At such a point, knowledge of using the CLI comes in handy.</p>
<p>There's a general notion that the CLI is difficult to use – and it does take some getting used to. But once you get acquainted with the operations of CLI you'll find it much easier to manage.   </p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
