<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Scott Robinson</title>
    <description>The latest articles on DEV Community by Scott Robinson (@scottwrobinson).</description>
    <link>https://dev.to/scottwrobinson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F381385%2Fe0511327-ba03-4381-862d-62ca102530e4.jpg</url>
      <title>DEV Community: Scott Robinson</title>
      <link>https://dev.to/scottwrobinson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/scottwrobinson"/>
    <language>en</language>
    <item>
      <title>Fast and Consistent Deployments with Terraform</title>
      <dc:creator>Scott Robinson</dc:creator>
      <pubDate>Thu, 30 May 2024 22:33:44 +0000</pubDate>
      <link>https://dev.to/scottwrobinson/fast-and-consistent-deployments-with-terraform-43k</link>
      <guid>https://dev.to/scottwrobinson/fast-and-consistent-deployments-with-terraform-43k</guid>
      <description>&lt;p&gt;Most types of internet-first businesses have become incredibly competitive. You're not just competing with people in your town, but everyone around the world. Because of this, the speed at which you can launch new products and features can be the difference between success and failure. This is why it is important to have a good infrastructure in place that allows you to not only launch fast, but update fast too.&lt;/p&gt;

&lt;p&gt;In this article, I'll be giving a brief overview of Terraform and show you how I used it to launch my new monitoring tool, &lt;a href="https://pingbot.dev"&gt;Ping Bot&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Terraform?
&lt;/h2&gt;

&lt;p&gt;Terraform is an open-source &lt;strong&gt;infrastructure as code&lt;/strong&gt; software tool created by HashiCorp. It lets you define and provision data center infrastructure using a declarative configuration language. Terraform manages external resources like public cloud infrastructure, private cloud infrastructure, network appliances, software as a service, platform as a service, DNS, and a whole lot more with a code.&lt;/p&gt;

&lt;p&gt;Let's see a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0c55b159cbfafe1f0"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will create an EC2 instance in the &lt;code&gt;us-west-2&lt;/code&gt; region with the &lt;code&gt;t2.micro&lt;/code&gt; instance type. You could do the same thing for most other cloud providers, like Azure, Google Cloud, and Digital Ocean.&lt;/p&gt;

&lt;p&gt;For a single instance, Terraform doesn't give you much of an advantage. But when you add in all of the other resources and configurations, it becomes a powerful tool. Not just for the time-saving, but consistency and repeatability as well. If your service only uses a small number of resources, you might not see the benefits of Terraform.&lt;/p&gt;

&lt;p&gt;There are 3 main reasons I decided to use Terraform:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: I wanted to be able to launch my products as fast as possible. Terraform allowed me to quickly create all of the resources I needed in AWS. From servers to databases to S3 buckets, I could do it all with a single command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: I wanted to make sure that my infrastructure was consistent across all of my environments. When you have dozens of resources, manually creating and configuring them can lead to mistakes. Terraform ensures that everything is created the same way every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeatability&lt;/strong&gt;: I wanted to be able to easily recreate my infrastructure in case of a disaster. If something were to happen to my AWS account or I needed to transfer accounts, I could easily recreate everything.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Terraform Setup
&lt;/h2&gt;

&lt;p&gt;Before we get ahead of ourselves, let's talk about setup. There are a ton of resources on &lt;a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli"&gt;installing&lt;/a&gt; and using Terraform, so in this article I'll mostly be talking about how I used it. This kind of setup is probably best for single-person projects or small teams. For larger teams, you might want to look into more advanced configurations and tooling.&lt;/p&gt;

&lt;p&gt;If you're like me, you have a few different AWS accounts for different projects. Because of this, I've set up my different profiles in the &lt;code&gt;~/.aws/credentials&lt;/code&gt; file. This allows me to easily switch between accounts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[default]&lt;/span&gt;
&lt;span class="py"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;
&lt;span class="py"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;

&lt;span class="nn"&gt;[pingbot]&lt;/span&gt;
&lt;span class="py"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;
&lt;span class="py"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can then use this in my Terraform config to switch between AWS accounts, depending on which environtment I want to deploy to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
  &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"pingbot"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also took advantage of Terraform's workspace feature. This allows you to have multiple environments, like &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, and &lt;code&gt;production&lt;/code&gt;, all in the same codebase. This is great because you can easily test changes in a safe environment before deploying to production.&lt;/p&gt;

&lt;p&gt;Once I've created my workspaces with &lt;code&gt;terraform workspace new [NAME]&lt;/code&gt;, I can switch between them with &lt;code&gt;terraform workspace select [NAME]&lt;/code&gt;. Then in my configuration code, I use the workspace throughout to create different resources based on the environment. This can be done using &lt;code&gt;locals&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dev&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-dev"&lt;/span&gt;
    &lt;span class="nx"&gt;stage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-stage"&lt;/span&gt;
    &lt;span class="nx"&gt;prod&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dev&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
    &lt;span class="nx"&gt;stage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.medium"&lt;/span&gt;
    &lt;span class="nx"&gt;prod&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.large"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0c55b159cbfafe1f0"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_type&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"pingbot"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"pingbot${local.ns[terraform.workspace]}"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_route53_record"&lt;/span&gt; &lt;span class="s2"&gt;"pingbot"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;zone_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route53_zone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pingbot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zone_id&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;terraform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workspace&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"prod"&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;"pingbot.dev"&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"${terraform.workspace}.pingbot.dev"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"A"&lt;/span&gt;
  &lt;span class="nx"&gt;ttl&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"300"&lt;/span&gt;
  &lt;span class="nx"&gt;records&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pingbot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I'm changing the instance size, S3 bucket name, and Route53 record based on the workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules
&lt;/h2&gt;

&lt;p&gt;One of the most powerful features of Terraform is modules. Modules are reusable Terraform configurations that can be called multiple times. This is great for creating reusable components that can be used multiple times in a project or shared across different projects.&lt;/p&gt;

&lt;p&gt;For exampale, with Ping Bot I wanted to be able to &lt;a href="https://pingbot.dev"&gt;monitor infrastructure&lt;/a&gt; for our customers from multiple locations around the world. Manually creating these resources in different AWS regions would've been tedious and error-prone. Instead, I created a module that would create the SQS queues and Lambdas in each location and installs the necessary software to run the pings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"ping_infra"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./modules/ping_infra"&lt;/span&gt;

  &lt;span class="nx"&gt;locations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ap-southeast-1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of taking an hour or two to set up ping infra in the Asia Pacific region, for example, I can do it in a few minutes with a single line change and &lt;code&gt;terraform apply&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;A lot of teams are also pretty opinionated about how they want their infrastructure set up. By creating modules, you can create a standard way of doing things that everyone can use. This can help with onboarding new team members and make it easier to move between projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cons of Terraform
&lt;/h2&gt;

&lt;p&gt;While Terraform is a great tool, it's not without its downsides. Here are a few things to consider before using it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Terraform can be complex, especially when you start using modules and more advanced features. This can make it hard for new team members to get up to speed if your setup isn't well thought-out or you don't have someone who specifically owns the process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State Management&lt;/strong&gt;: Terraform uses a state file to keep track of the resources it creates. This file can get out of sync with your actual infrastructure if you're not careful. This can lead to some pretty bad situations if you're not careful. You'll often find yourself needing to migrate state as files change, which can be a huge pain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;: Terraform has a bit of a learning curve. While the basics are pretty easy to pick up, the more advanced features and edge cases can be confusing, especially for more junior developers. This can make it hard to get started if you're not already familiar with infrastructure as code tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost&lt;/strong&gt;: Terraform can be expensive, especially if you're using it to manage a lot of resources. This isn't exactly Terraform's fault, but when your resources just become code, it's easy to lose track of what you're actually spending. This can lead to some pretty big bills if you're not careful. Self-funded startups, in particular, should be careful!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Terraform is a powerful tool that can help you launch faster and more consistently. By defining your infrastructure as code, you can easily create and manage resources across multiple environments. This can help you move faster and reduce the risk of mistakes. While it's definitely not perfect, it's a great tool to have in your toolbox if you're looking to launch fast and stay competitive.&lt;/p&gt;

&lt;p&gt;Thoughts? Feedback? I'd love to hear from you - there are plenty of places to &lt;a href="https://linktr.ee/scottwrobinson"&gt;reach me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>saas</category>
      <category>devops</category>
    </item>
    <item>
      <title>Using to the Gmail API with Node.js</title>
      <dc:creator>Scott Robinson</dc:creator>
      <pubDate>Wed, 16 Aug 2023 16:57:41 +0000</pubDate>
      <link>https://dev.to/scottwrobinson/using-to-the-gmail-api-with-nodejs-51kh</link>
      <guid>https://dev.to/scottwrobinson/using-to-the-gmail-api-with-nodejs-51kh</guid>
      <description>&lt;p&gt;It's easy to think of a ton of reasons for wanting to connect to your Gmail account programmatically, whether it's to create a bot to send emails on your behalf, or maybe to create your own custom spam filter. There are also endless SaaS ideas for connecting to users' accounts and offering a service on top of Gmail.&lt;/p&gt;

&lt;p&gt;Luckily, the Gmail API offers a nice way to manage a Gmail account. With Node.js, we can easily create applications that integrate directly with Gmail. In this article, I'll show how to set up a project, create a Gmail API client, and kickstart your journey with the Gmail API using Node.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the Project
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, let's first set up a new Node.js project. Make sure you have &lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt; installed on your system, and then follow the steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create the project folder:&lt;/strong&gt; Open your terminal and navigate to where you want your project to reside. Then create a new directory:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;gmail-api-project
   &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;gmail-api-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a new project:&lt;/strong&gt; Run the following command and follow the prompts:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;$ &lt;/span&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-y&lt;/code&gt; parameter tells &lt;code&gt;npm&lt;/code&gt; to enter "yes" for all the questions during the init process. So basically, just use all of the defaults.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install dependencies:&lt;/strong&gt; We'll be using the &lt;code&gt;googleapis&lt;/code&gt; package, so go ahead and install it:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;googleapis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Make sure your Node.js version is 10.x or higher, as the Gmail API client may not work correctly with older versions.&lt;/p&gt;

&lt;p&gt;The project is now set up and we can move on to creating the actual Gmail API client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Gmail API Client
&lt;/h2&gt;

&lt;p&gt;The Gmail API client is the bridge between your code and Gmail. Here's how to create it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create credentials in Google Cloud Console:&lt;/strong&gt; Go to the &lt;a href="https://console.cloud.google.com/"&gt;Google Cloud Console&lt;/a&gt; and create a project. Then navigate to "API &amp;amp; Services" &amp;gt; "Dashboard" &amp;gt; "Enable APIs and Services" &amp;gt; search for "Gmail API" and enable it. Now create credentials (OAuth client ID) and download the JSON file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load client libraries and credentials:&lt;/strong&gt; In your project folder, create a new file &lt;code&gt;index.js&lt;/code&gt; and add the following code to load the Gmail client libraries and your credentials:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;googleapis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./path/to/credentials.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OAuth2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_REDIRECT_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Authorize the client:&lt;/strong&gt; Your app will need to obtain an access token to authenticate with Gmail. You can use these tokens by using the following code snippet:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="c1"&gt;// Load token or redirect to auth URL&lt;/span&gt;
   &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="c1"&gt;// Create Gmail client&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure to replace &lt;code&gt;'YOUR_REDIRECT_URL'&lt;/code&gt; with the redirect URL you've specified in the Google Cloud Console when creating your OAuth client ID!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In order to obtain the access token, you'll need to set up a way to complete the OAuth flow, which can be done using a few different methods. One possible method to is create an HTTP route that accepts the OAuth credentials and data, but that is outside the scope of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving Emails
&lt;/h2&gt;

&lt;p&gt;Now that you've set up the Gmail API client, retrieving emails is the next step. Here's how to fetch the emails from your Gmail account with Node.js:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use the &lt;code&gt;list&lt;/code&gt; method:&lt;/strong&gt; You can use the &lt;code&gt;list&lt;/code&gt; method of the Gmail API to fetch emails. For example, let's fetch the last 10 emails:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;maxResults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get the details of each message:&lt;/strong&gt; You'll need to call the &lt;code&gt;get&lt;/code&gt; method for each message to get the full details:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
       &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Subject: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;list&lt;/code&gt; method returns a summary of the messages, so calling the &lt;code&gt;get&lt;/code&gt; method for each one is needed to get the rest of the email data.&lt;/p&gt;

&lt;p&gt;When creating &lt;a href="https://blocksender.io/"&gt;blocksender.io&lt;/a&gt;, I found out the hard way that you'll need &lt;em&gt;a lot&lt;/em&gt; of error checking, retries, etc when retrieving emails. The Gmail API often returns HTTP 500 statuses and has lots of edge cases. So make sure you test your applications thoroughly and handle as many potential issues as possible in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending an Email
&lt;/h2&gt;

&lt;p&gt;Now that we know how to fetch emails, let's learn how to send an email using the Gmail API.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create the email content:&lt;/strong&gt; First, we need to create the email body. You'll have to convert it to a Base64-encoded string:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailLines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;From: sender@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;To: receiver@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-type: text/html;charset=iso-8859-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MIME-Version: 1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Subject: Test Subject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is a test email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="p"&gt;];&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;emailLines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base64Email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use the &lt;code&gt;send&lt;/code&gt; method:&lt;/strong&gt; Now, you can use the &lt;code&gt;send&lt;/code&gt; method to actually send the email via the API:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;base64Email&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it, you've just sent an email using the Gmail API 👍&lt;/p&gt;

</description>
      <category>node</category>
      <category>gmail</category>
      <category>api</category>
    </item>
    <item>
      <title>Python's os and subprocess Popen Commands</title>
      <dc:creator>Scott Robinson</dc:creator>
      <pubDate>Thu, 18 Jun 2020 14:24:57 +0000</pubDate>
      <link>https://dev.to/scottwrobinson/python-s-os-and-subprocess-popen-commands-25i2</link>
      <guid>https://dev.to/scottwrobinson/python-s-os-and-subprocess-popen-commands-25i2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally posted on &lt;a href="https://stackabuse.com/pythons-os-and-subprocess-popen-commands/"&gt;StackAbuse.com&lt;/a&gt;. Check it out for more articles, guides, and more. 👍&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Python offers several options to run external processes and interact with the operating system. However, the methods are different for Python 2 and 3. Python 2 has several methods in the &lt;code&gt;os&lt;/code&gt; module, which are now deprecated and replaced by the &lt;code&gt;subprocess&lt;/code&gt; module, which is the preferred option in Python 3.&lt;/p&gt;

&lt;p&gt;Throughout this article we'll talk about the various &lt;code&gt;os&lt;/code&gt; and &lt;code&gt;subprocess&lt;/code&gt; methods, how to use them, how they're different from each other, on what version of Python they should be used, and even how to convert the older commands to the newer ones.&lt;/p&gt;

&lt;p&gt;Hopefully by the end of this article you'll have a better understanding of how to call external commands from Python code and which method you should use to do it.&lt;/p&gt;

&lt;p&gt;First up is the older &lt;code&gt;os.popen*&lt;/code&gt; methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  The os.popen* Methods
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;os&lt;/code&gt; module offers four different methods that allows us to interact with the operating system (just like you would with the command line) and create a &lt;a href="https://en.wikipedia.org/wiki/Pipeline_(Unix)"&gt;pipe&lt;/a&gt; to other commands. These methods I'm referring to are: &lt;code&gt;popen&lt;/code&gt;, &lt;code&gt;popen2&lt;/code&gt;, &lt;code&gt;popen3&lt;/code&gt;, and &lt;code&gt;popen4&lt;/code&gt;, all of which are described in the following sections.&lt;/p&gt;

&lt;p&gt;The goal of each of these methods is to be able to call other programs from your Python code. This could be calling another executable, like your own compiled C++ program, or a shell command like &lt;code&gt;ls&lt;/code&gt; or &lt;code&gt;mkdir&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  os.popen
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;os.popen&lt;/code&gt; method opens a pipe from a command. This pipe allows the command to send its output to another command. The output is an open file that can be accessed by other programs.&lt;/p&gt;

&lt;p&gt;The syntax is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;bufsize&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the &lt;code&gt;command&lt;/code&gt; parameter is what you'll be executing, and its output will be available via an open file. The argument &lt;code&gt;mode&lt;/code&gt; defines whether or not this output file is readable ('r') or writable ('w'). Appending a 'b' to the &lt;code&gt;mode&lt;/code&gt; will open the file in binary mode. Thus, for example "rb" will produce a readable binary file object.&lt;/p&gt;

&lt;p&gt;In order to retrieve the exit code of the command executed, you must use the &lt;code&gt;close()&lt;/code&gt; method of the file object.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;bufsize&lt;/code&gt; parameter tells &lt;code&gt;popen&lt;/code&gt; how much data to buffer, and can assume one of the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0 = unbuffered (default value)&lt;/li&gt;
&lt;li&gt;1 = line buffered&lt;/li&gt;
&lt;li&gt;N = approximate buffer size, when N &amp;gt; 0; and default value, when N &amp;lt; 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This method is available for Unix and Windows platforms, and has been deprecated since Python version 2.6. If you're currently using this method and want to switch to the Python 3 version, here is the equivalent &lt;code&gt;subprocess&lt;/code&gt; version for Python 3:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Replaced by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pipe = os.popen('cmd', 'r', bufsize)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pipe = Popen('cmd', shell=True, bufsize=bufsize, stdout=PIPE).stdout&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pipe = os.popen('cmd', 'w', bufsize)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pipe = Popen('cmd', shell=True, bufsize=bufsize, stdin=PIPE).stdin&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The code below shows an example of how to use the &lt;code&gt;os.popen&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ls -la&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above will ask the operating system to list all files in the current directory. The output of our method, which is stored in &lt;code&gt;p&lt;/code&gt;, is an open file, which is read and printed in the last line of the code. The of this code (in the context of my current directory) result is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python popen_test.py 
&lt;span class="go"&gt;total 32
drwxr-xr-x   7 scott  staff  238 Nov  9 09:13 .
drwxr-xr-x  29 scott  staff  986 Nov  9 09:08 ..
-rw-r--r--   1 scott  staff   52 Nov  9 09:13 popen2_test.py
-rw-r--r--   1 scott  staff   55 Nov  9 09:14 popen3_test.py
-rw-r--r--   1 scott  staff   53 Nov  9 09:14 popen4_test.py
-rw-r--r--   1 scott  staff   49 Nov  9 09:13 popen_test.py
-rw-r--r--   1 scott  staff    0 Nov  9 09:13 subprocess_popen_test.py
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  os.popen2
&lt;/h4&gt;

&lt;p&gt;This method is very similar to the previous one. The main difference is what the method outputs. In this case it returns two file objects, one for the &lt;a href="https://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29"&gt;stdin&lt;/a&gt; and another file for the &lt;a href="https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29"&gt;stdout&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The syntax is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;popen2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;bufsize&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These arguments have the same meaning as in the previous method, &lt;code&gt;os.popen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;popen2&lt;/code&gt; method is available for both the Unix and Windows platforms. However, it is found only in Python 2. Again, if you want to use the &lt;code&gt;subprocess&lt;/code&gt; version instead (shown in more detail below), use the following instead:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Replaced by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(child_stdin, child_stdout) = os.popen2('cmd', mode, bufsize)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;p = Popen('cmd', shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)&lt;/code&gt;&lt;br&gt;&lt;code&gt;(child_stdin, child_stdout) = (p.stdin, p.stdout)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The code below shows an example on how to use this method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popen2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ls -la&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will produce the same results as shown in the first code output above. The difference here is that the output of the &lt;code&gt;popen2&lt;/code&gt; method consists of two files. Thus, the 2nd line of code defines two variables: &lt;code&gt;in&lt;/code&gt; and &lt;code&gt;out&lt;/code&gt;. In the last line, we read the output file &lt;code&gt;out&lt;/code&gt; and print it to the console.&lt;/p&gt;

&lt;h4&gt;
  
  
  os.popen3
&lt;/h4&gt;

&lt;p&gt;This method is very similar to the previous ones. However, the difference is that the output of the command is a set of three files: stdin, stdout, and &lt;a href="https://en.wikipedia.org/wiki/Standard_streams#Standard_error_.28stderr.29"&gt;stderr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popen3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="n"&gt;bufsize&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where the arguments &lt;code&gt;cmd&lt;/code&gt;, &lt;code&gt;mode&lt;/code&gt;, and &lt;code&gt;bufsize&lt;/code&gt; have the same specifications as in the previous methods. The method is available for Unix and Windows platforms.&lt;/p&gt;

&lt;p&gt;Note that this method has been deprecated and the Python documentation advises us to replace the &lt;code&gt;popen3&lt;/code&gt; method as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Replaced by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(child_stdin, child_stdout, child_stderr) = os.popen3('cmd', mode, bufsize)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;p = Popen('cmd', shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)&lt;/code&gt;&lt;br&gt;&lt;code&gt;(child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As in the previous examples, the code below will produce the same result as seen in our first example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popen3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ls -la&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in this case, we have to define three files: stdin, stdout, and stderr. The list of files from our &lt;code&gt;ls -la&lt;/code&gt; command is saved in the &lt;code&gt;out&lt;/code&gt; file.&lt;/p&gt;

&lt;h4&gt;
  
  
  os.popen4
&lt;/h4&gt;

&lt;p&gt;As you probably guessed, the &lt;code&gt;os.popen4&lt;/code&gt; method is similar to the previous methods. However, in this case, it returns only two files, one for the stdin, and another one for the stdout &lt;em&gt;and&lt;/em&gt; the stderr.&lt;/p&gt;

&lt;p&gt;This method is available for the Unix and Windows platforms and (&lt;em&gt;surprise!&lt;/em&gt;) has also been deprecated since version 2.6. To replace it with the corresponding &lt;code&gt;subprocess&lt;/code&gt; &lt;code&gt;Popen&lt;/code&gt; call, do the following:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Replaced by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(child_stdin, child_stdout_and_stderr) = os.popen4('cmd', mode, bufsize)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;p = Popen('cmd', shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)&lt;/code&gt;&lt;br&gt;&lt;code&gt;(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The following code will produce the same result as in the previous examples, which is shown in the first code output above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popen4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ls -la&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;we&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see from the code above, the method looks very similar to &lt;code&gt;popen2&lt;/code&gt;. However, the &lt;code&gt;out&lt;/code&gt; file in the program will show the combined results of both the stdout and the stderr streams.&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary of differences
&lt;/h4&gt;

&lt;p&gt;The differences between the different &lt;code&gt;popen*&lt;/code&gt; commands all have to do with their output, which is summarized in the table below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Arguments&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;popen&lt;/td&gt;
&lt;td&gt;stdout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;popen2&lt;/td&gt;
&lt;td&gt;stdin, stdout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;popen3&lt;/td&gt;
&lt;td&gt;stdin, stdout, stderr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;popen4&lt;/td&gt;
&lt;td&gt;stdin, stdout and stderr&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In addition the &lt;code&gt;popen2&lt;/code&gt;, &lt;code&gt;popen3&lt;/code&gt;, and &lt;code&gt;popen4&lt;/code&gt; are only available in Python 2 but not in Python 3. Python 3 has available the &lt;code&gt;popen&lt;/code&gt; method, but it is recommended to use the &lt;code&gt;subprocess&lt;/code&gt; module instead, which we'll describe in more detail in the following section.&lt;/p&gt;

&lt;h3&gt;
  
  
  The susbprocess.Popen Method
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.python.org/3/library/subprocess.html"&gt;subprocess module&lt;/a&gt; was created with the intention of replacing several methods available in the &lt;code&gt;os&lt;/code&gt; module, which were not considered to be very efficient. Within this module, we find the new &lt;code&gt;Popen&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The Python documentation recommends the use of &lt;code&gt;Popen&lt;/code&gt; in advanced cases, when other methods such like &lt;code&gt;subprocess.call&lt;/code&gt; cannot fulfill our needs. This method allows for the execution of a program as a child process. Because this is executed by the operating system as a separate process, the results are platform dependent.&lt;/p&gt;

&lt;p&gt;The available parameters are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bufsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;executable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;preexec_fn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;close_fds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;universal_newlines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startupinfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;creationflags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One main difference of &lt;code&gt;Popen&lt;/code&gt; is that it is a class and not just a method. Thus, when we call &lt;code&gt;subprocess.Popen&lt;/code&gt;, we're actually calling the constructor of the class &lt;code&gt;Popen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are quite a few arguments in the constructor. The most important to understand is &lt;code&gt;args&lt;/code&gt;, which contains the command for the process we want to run. It can be specified as a sequence of parameters (via an array) or as a single command string.&lt;/p&gt;

&lt;p&gt;The second argument that is important to understand is &lt;code&gt;shell&lt;/code&gt;, which is defaults to &lt;code&gt;False&lt;/code&gt;. On Unix, when we need to run a command that belongs to the shell, like &lt;code&gt;ls -la&lt;/code&gt;, we need to set &lt;code&gt;shell=True&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, the following code will call the Unix command &lt;code&gt;ls -la&lt;/code&gt; via a shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ls -la&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The results can be seen in the output below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python subprocess_popen_test.py 
total 40
drwxr-xr-x   7 scott  staff  238 Nov  9 09:13 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x  29 scott  staff  986 Nov  9 09:08 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;   1 scott  staff   52 Nov  9 09:13 popen2_test.py
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;   1 scott  staff   55 Nov  9 09:14 popen3_test.py
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;   1 scott  staff   53 Nov  9 09:14 popen4_test.py
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;   1 scott  staff   49 Nov  9 09:13 popen_test.py
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;   1 scott  staff   56 Nov  9 09:16 subprocess_popen_test.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the following example from a Windows machine, we can see the differences of using the &lt;code&gt;shell&lt;/code&gt; parameter more easily. Here we're opening Microsoft Excel from the shell, or as an executable program. From the shell, it is just like if we were opening Excel from a command window.&lt;/p&gt;

&lt;p&gt;The following code will open Excel from the shell (note that we have to specify &lt;code&gt;shell=True&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start excel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, we can get the same results by calling the Excel executable. In this case we are not using the shell, so we leave it with its default value (&lt;code&gt;False&lt;/code&gt;); but we have to specify the full path to the executable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;C:\Program Files (x86)\Microsoft Office\Office15\excel.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, when we instantiate the &lt;code&gt;Popen&lt;/code&gt; class, we have access to several useful methods:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Popen.poll()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Checks if the child process has terminated.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Popen.wait()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wait for the child process to terminate.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Popen.communicate()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allows to interact with the process.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Popen.send_signal()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sends a signal to the child process.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Popen.terminate()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stops the child process.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Popen.kill()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kills a child process.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The full list can be found at the &lt;a href="https://docs.python.org/2/library/subprocess.html"&gt;subprocess documentation&lt;/a&gt;. The most commonly used method here is &lt;code&gt;communicate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;communicate&lt;/code&gt; method allows us to read data from the standard input, and it also allows us to send data to the standard output. It returns a tuple defined as &lt;code&gt;(stdoutdata, stderrdata)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, the following code will combine the Windows &lt;code&gt;dir&lt;/code&gt; and &lt;code&gt;sort&lt;/code&gt; commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;

&lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dir&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sort /R&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;communicate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to combine both commands, we create two subprocesses, one for the &lt;code&gt;dir&lt;/code&gt; command and another for the &lt;code&gt;sort&lt;/code&gt; command. Since we want to sort in reverse order, we add &lt;code&gt;/R&lt;/code&gt; option to the &lt;code&gt;sort&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;We define the stdout of process 1 as PIPE, which allows us to use the output of process 1 as the input for process 2. Then we need to close the stdout of process 1, so it can be used as input by process 2. The communication between process is achieved via the &lt;code&gt;communicate&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Running this from a Windows command shell produces the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; python subprocess_pipe_test.py
11/09/2019  08:52 PM                  234 subprocess_pipe_test.py
11/09/2019  07:13 PM                   99 subprocess_pipe_test2.py
11/09/2019  07:08 PM                   66 subprocess_pipe_test3.py
11/09/2019  07:01 PM                   56 subprocess_pipe_test4.py
11/09/2019  06:48 PM     &amp;lt;DIR&amp;gt;            ..
11/09/2019  06:48 PM     &amp;lt;DIR&amp;gt;            .
 Volume Serial Number is 2E4E-56A3
 Volume in drive D is ECA
 Directory of D:\MyPopen
               4 File(s)            455 bytes
               2 Dir(s)  18,634,326,016 bytes free
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;os&lt;/code&gt; methods presented a good option in the past, however, at present the &lt;code&gt;subprocess&lt;/code&gt; module has several methods which are more powerful and efficient to use. Among the tools available is the &lt;code&gt;Popen&lt;/code&gt; class, which can be used in more complex cases. This class also contains the &lt;code&gt;communicate&lt;/code&gt; method, which helps us pipe together different commands for more complex functionality.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Check us out over at &lt;a href="https://stackabuse.com/"&gt;StackAbuse.com&lt;/a&gt; for more articles, guides, and other resources. You can also follow us &lt;a href="https://twitter.com/stackabuse"&gt;@StackAbuse&lt;/a&gt; for new articles daily.&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>Zsh vs Bash</title>
      <dc:creator>Scott Robinson</dc:creator>
      <pubDate>Tue, 09 Jun 2020 15:03:07 +0000</pubDate>
      <link>https://dev.to/scottwrobinson/zsh-vs-bash-7ik</link>
      <guid>https://dev.to/scottwrobinson/zsh-vs-bash-7ik</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally posted on &lt;a href="https://stackabuse.com/"&gt;StackAbuse.com&lt;/a&gt;. Check it out for more articles, guides, and more. 👍&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When we talk about Unix-based programming, it's usually about the shells, terminals, and the command line interfaces. The most prevalent shell in this regard is &lt;a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)"&gt;Bash&lt;/a&gt; but there are other variants available and used widely as well, like Zsh, or the &lt;a href="https://en.wikipedia.org/wiki/Z_shell"&gt;Z shell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we'll attempt to draw the line between the two shells and show the differences so you can get a sense of why you might use one or the other. But first, in the following sections we'll introduce both shells before we compare them together. &lt;/p&gt;

&lt;h1&gt;
  
  
  Z Shell
&lt;/h1&gt;

&lt;p&gt;Zsh, or Z shell, was first released by Paul Falstad back in 1990 when he was still a student at Princeton University. Z shell is included in many operating systems, including Mac OS (although it isn't the default that's actually used).&lt;/p&gt;

&lt;p&gt;Much like Bash, Z shell can basically be seen as an extended version of the &lt;a href="https://en.wikipedia.org/wiki/Bourne_shell"&gt;Bourne shell&lt;/a&gt;, and does contain a lot of the same features as Bash, which you'll probably notice in the sections below. You may also notice that it pretty closely resembles the Korn shell as well. Some of the features that are worth mentioning include (but are not limited to):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File &lt;a href="https://en.wikipedia.org/wiki/Glob_(programming)"&gt;globbing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Spelling correction&lt;/li&gt;
&lt;li&gt;Directory aliases (much like &lt;code&gt;~&lt;/code&gt; or &lt;code&gt;..&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Loadable modules, like socket controls or an FTP client&lt;/li&gt;
&lt;li&gt;Compatibility modes: e.g. You can use &lt;code&gt;/bin/bash&lt;/code&gt; as a drop-in replacement for Bash&lt;/li&gt;
&lt;li&gt;Startup/shutdown scripts via &lt;code&gt;zshenv&lt;/code&gt;, &lt;code&gt;zprofile&lt;/code&gt;, &lt;code&gt;zshrc&lt;/code&gt;, &lt;code&gt;zlogin&lt;/code&gt;, and &lt;code&gt;zlogout&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git&lt;/code&gt; command completion&lt;/li&gt;
&lt;li&gt;Path expansion: e.g. Enter &lt;code&gt;cd /u/lo/b&lt;/code&gt;, press tab, and it will be completed to &lt;code&gt;cd /usr/local/bin&lt;/code&gt; since it is the only matching pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are &lt;em&gt;a lot&lt;/em&gt; more features than what we've shown here, but at least this gives you an idea as to how shells can be different.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bash
&lt;/h1&gt;

&lt;p&gt;The Bash shell (also known as the "Bourne-again shell") was also released around the same period as the Z shell (in 1989) and Brian Fox is regarded as the creator behind it. It was initially written as a replacement for the Bourne shell. For many years it has shipped as the default shell for GNU, most Linux distributions, and Mac OS X (version 10.3+). Like a true replacement should, Bash is capable of executing all of the Bourne shell commands without a problem.&lt;/p&gt;

&lt;p&gt;There are quite a few features that the Bash shell has and some of the lesser-known ones include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insert the last parameter(s) of the preceding command in your current command using &lt;code&gt;Alt&lt;/code&gt; + &lt;code&gt;.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You can keep a process running even after logging out. To do so, use the command &lt;code&gt;disown -h &amp;lt;pid&amp;gt;&lt;/code&gt; where you will have to place the process ID (PID) of the program instead of &lt;code&gt;&amp;lt;pid&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Execute the previous command again, but this time running with &lt;code&gt;sudo&lt;/code&gt; using the command &lt;code&gt;sudo !!&lt;/code&gt; (&lt;code&gt;!!&lt;/code&gt; is shorthand for 'the previous command')&lt;/li&gt;
&lt;li&gt;Perform a reverse incremental search using the &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;R&lt;/code&gt; keys&lt;/li&gt;
&lt;li&gt;Press tab twice and you will see the list of completions for the word that you have just typed or are typing&lt;/li&gt;
&lt;li&gt;When executing a script with &lt;code&gt;bash&lt;/code&gt;, use the &lt;code&gt;-x&lt;/code&gt; option to output the script contents as it's being executed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to learn more, you can see a much larger list of Bash-specific features &lt;a href="http://web.mit.edu/gnu/doc/html/features_4.html#SEC20"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Comparing Z shell and Bash
&lt;/h1&gt;

&lt;p&gt;Now that we've give you a brief introduction to both of the shells, let's see how they hold up when actually compared and contrasted together.&lt;/p&gt;

&lt;p&gt;The first thing to look at (and one of the more significant aspects, in my opinion) is prevalence and popularity of the shell. While the Z shell has its fair share of users throughout the developer community, it's usually safer to write your scripts for Bash since there is a much larger group of people that will be able to run those scripts.&lt;/p&gt;

&lt;p&gt;The importance of adoption holds true for the public resources and documentation as well. Thanks to its large community, Bash has quite a few more resources out there to help you learn how to use it.&lt;/p&gt;

&lt;p&gt;So, if you are planning on writing a script that you want many developers to easily be able to run then I'd recommend that you go with Bash. However, this shouldn't stop you from using Z shell if your end goal is more suited to Z shell. Finding the right solution to a problem is much more important than just using what's popular, so keep that in mind as well.&lt;/p&gt;

&lt;p&gt;Although Bash is much more popular, that doesn't mean Z shell is without any useful features of its own. It's actually heavily praised for its interactive use, because it's more customizable than Bash. For example, the prompts are more flexible. It can display a prompt on the left &lt;em&gt;and&lt;/em&gt; another on the right side of the screen, much like vim's split screen. The auto-completion is also more customizable and is actually faster than Bash's.&lt;/p&gt;

&lt;p&gt;To give you a better sense of what kind of features Z shell has, here is a list of things that you will have access to when using Z shell over Bash:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The built-in &lt;code&gt;zmv&lt;/code&gt; command can help you do massive file/directory renames. e.g. to append '.txt' to every file name run &lt;code&gt;zmv –C '(*)(#q.)' '$1.txt'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;zcalc&lt;/code&gt; utility is a great command-line calculator which is a convenient way to do a quick calculation without leaving the terminal. Load it with &lt;code&gt;autoload -Uz zcalc&lt;/code&gt; and run with &lt;code&gt;zcalc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;zparseopts&lt;/code&gt; command is a one-liner that lets you to parse complex options that are provided to your script&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;autopushd&lt;/code&gt; command helps you do &lt;code&gt;popd&lt;/code&gt; after you use &lt;code&gt;cd&lt;/code&gt; to go back to your previous directory&lt;/li&gt;
&lt;li&gt;Floating point support (which Bash suprisingly &lt;em&gt;does not&lt;/em&gt; have)&lt;/li&gt;
&lt;li&gt;Support for hash data structures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also a bunch of features that are present in the Bash terminal but are absent from almost all of the other shells. Here are a few of them as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;–norc&lt;/code&gt; command-line option, which allows the user to proceed with the shell initialization &lt;em&gt;without&lt;/em&gt; reading the &lt;code&gt;bash.rc&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Using the option &lt;code&gt;–rcfile &amp;lt;filename&amp;gt;&lt;/code&gt; with &lt;code&gt;bash&lt;/code&gt; allows you to execute commands from the specified file&lt;/li&gt;
&lt;li&gt;Excellent &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Invoking-Bash.html"&gt;invocation features&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Can be invoked with the &lt;code&gt;sh&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;Bash can be run in a specific POSIX mode. Use &lt;code&gt;set –o posix&lt;/code&gt; to invoke the mode or &lt;code&gt;--posix&lt;/code&gt; on startup&lt;/li&gt;
&lt;li&gt;You can control the look of the prompt in Bash. Setting the &lt;code&gt;PROMPT_COMMAND&lt;/code&gt; variable to one or more of the &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Controlling-the-Prompt.html"&gt;special characters&lt;/a&gt; will customize it for you&lt;/li&gt;
&lt;li&gt;Bash can also be invoked as a &lt;a href="https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html"&gt;restricted shell&lt;/a&gt; (with &lt;code&gt;rbash&lt;/code&gt; or &lt;code&gt;--restricted&lt;/code&gt;), which means certain commands/actions are no longer allowed, such as:

&lt;ul&gt;
&lt;li&gt;Setting or unsetting the values of the &lt;code&gt;SHELL&lt;/code&gt;, &lt;code&gt;PATH&lt;/code&gt;, &lt;code&gt;ENV&lt;/code&gt;, or &lt;code&gt;BASH_ENV&lt;/code&gt; variables&lt;/li&gt;
&lt;li&gt;Redirecting output using the &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;|&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; redirection operators&lt;/li&gt;
&lt;li&gt;Parsing the value of SHELLOPTS from the shell environment at startup&lt;/li&gt;
&lt;li&gt;Using the exec builtin to replace the shell with another command.&lt;/li&gt;
&lt;li&gt;And many more...&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's difficult to say which shell is actually better. It all really depends on your own preferences and what you actually want to do with the shell. In the case of Bash vs Z shell, neither is really better than the other.&lt;/p&gt;

&lt;p&gt;There are quite a few fans of the Z shell throughout the developer community who advocate for it quite heavily thanks to the many useful features it provides. On the other side, there are even more fans of Bash who know that their biggest advantage is their far larger user base. It's easy to see why it is so difficult to get developers to switch from Z shell to Bash and vice versa.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Check us out over at &lt;a href="https://stackabuse.com/"&gt;StackAbuse.com&lt;/a&gt; for more articles, guides, and other resources. You can also follow us &lt;a href="https://twitter.com/stackabuse"&gt;@StackAbuse&lt;/a&gt; for new articles daily.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>zsh</category>
    </item>
  </channel>
</rss>
