Cross-Platform Command Line
Tags: devops, beginners, tutorial, productivity
Published: 2020-06-15 09:07:59

The command line can be daunting for many. And yet it is one of the most powerful tools we developers can have. And it's free!

So in this episode I want to help you get comfortable using your command line. You don't have to use it much, but there are some tasks that were just **made** for the command line. Also, this is a foundation for writing scripts for any operating system.

As part of my [Getting Started with DevOps series](https://brutalhack.com/blog/devops-getting-started/), this tutorial is cross-platform. We will be using PowerShell on **Windows** and bash (or zsh, they are compatible) on **macOS** and **Linux**.

Feel free to use this article as a reference to look up commands later:

*   [The Basics](#the-basics)
*   [Read the Manual](#read-the-manual)
*   [File Operations](#file-operations)
*   [The Wildcard](#the-wildcard)
*   [Executing Programs](#executing-programs)
*   [Make it fun to use!](#make-it-fun-to-use)
*   [Thefuck (plugin)](#thefuck-plugin)

## The Basics

First off, start your engines.

*   **Windows**: press the start button and search for a program called **PowerShell**.
*   **macOS**: Use [Spotlight](https://support.apple.com/en-us/HT204014) to launch **terminal.app**
*   **Linux**: Search for an application called **Terminal**. In Ubuntu, you can also press ctrl+alt+T

Now the first question to answer is: Where are we?

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># print working directory</span>
pwd
</pre>

</div>

This is one command for Windows, macOS and Linux. How can this be?  
The command line interface in macOS and Linux are identical (bash or another compatible shell like zsh, fish, etc).  
You can use most commands in both operating systems.  
And while Windows uses PowerShell, they have integrated aliases for unix commands. The output will often differ, but you get nearly the same information.

Now let's navigate around your file system with the following commands:

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># list files in directory</span>
ls

<span style="color: #008800; font-style: italic"># list all files in directory (includes hidden files)</span>
ls -al <span style="color: #008800; font-style: italic"># macOS and Linux</span>
ls -Hidden <span style="color: #008800; font-style: italic">#PowerShell</span>

<span style="color: #008800; font-style: italic"># change directory</span>
cd <DIRECTORY NAME>

<span style="color: #008800; font-style: italic"># leave directory / move up</span>
cd ..

<span style="color: #008800; font-style: italic"># go back to your $HOME directory</span>
cd ~
</pre>

</div>

So we can now navigate around our file systems, but typing the folder names takes long. Time to try out **tab-completion**.  
While typing anything in your terminal, you can often press tab to auto-complete your command, filename or directory name.  
Just a few examples to get you started:

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># cd to directory "Documents"</span>
cd Doc<span style="color: #880000;"><TAB></span>
<span style="color: #008800; font-style: italic"># => cd Documents</span>

<span style="color: #008800; font-style: italic"># list hidden files in PowerShell</span>
ls -Hi<span style="color: #880000;"><TAB></span>
<span style="color: #008800; font-style: italic"># => ls -Hidden</span>
</pre>

</div>

## Read the Manual

There are many commands coming up and both PowerShell and bash/zsh have manuals you can read on every single command.  
After all, this is just your beginning ;)

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># Show manual in PowerShell</span>
Get-Help <COMMAND> -Full

<span style="color: #008800; font-style: italic"># Show only examples in PowerShell</span>
Get-Help <COMMAND> -Examples

<span style="color: #008800; font-style: italic"># Show manual in macOS/Linux</span>
man <COMMAND>
<span style="color: #008800; font-style: italic"># Scroll with arrow keys up/down</span>
<span style="color: #008800; font-style: italic"># Close with Q</span>
</pre>

</div>

## File Operations

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># Create a new file</span>
touch <FILENAME>

<span style="color: #008800; font-style: italic"># Display file contents</span>
cat <FILENAME>

<span style="color: #008800; font-style: italic"># list target directory contents</span>
ls <DIRECTORY>
<span style="color: #008800; font-style: italic"># e.g. ls ~/Documents</span>
</pre>

</div>

So now that we can navigate through our file system, it‘s time for some interaction. Creating, Copying, Moving and removing files are the three basic operations I use everyday.

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># Move a file</span> 
mv <FILENAME> <TARGET-DIRECTORY>/
<span style="color: #008800; font-style: italic"># e.g. mv Documents/photo.jpg Pictures/</span>

<span style="color: #008800; font-style: italic"># With the move command you can also rename files</span>
mv <FILENAME> <TARGET-DIRECTORY>/<NEW-FILENAME>
<span style="color: #008800; font-style: italic"># e.g. mv Documents/photo.jpg Pictures/holiday-photo.jpg</span>
<span style="color: #008800; font-style: italic"># e.g. mv photo.jpg holiday-photo.jpg</span>

<span style="color: #008800; font-style: italic"># Remove a file</span>
rm <FILENAME>
</pre>

</div>

Now that we know how to work with files, we can alter these commands slightly to work with directories.

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># Move a directory</span> 
mv <DIRECTORY> <TARGET-DIRECTORY>/
<span style="color: #008800; font-style: italic"># e.g. mv Scanned-Pages ~/Documents/</span>

<span style="color: #008800; font-style: italic"># With the move command you can also rename directories</span>
mv <DIRECTORYNAME> <NEW-DIRECTORYNAME>
<span style="color: #008800; font-style: italic"># e.g. mv Scanned-Pages Scans</span>

<span style="color: #008800; font-style: italic"># Remove an empty directory</span>
rmdir <DIRECTORY>

<span style="color: #008800; font-style: italic"># Remove a directory with all its contents (careful with this one!)</span>
rm -rf <DIRECTORY>
</pre>

</div>

Take some time to get comfortable with these commands before you move on. The cool stuff is just ahead.

## The Wildcard

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># Show the content of all .txt files</span>
cat *.txt

<span style="color: #008800; font-style: italic"># Move Photo-london.jpg, Photo-tokio.jpg, Photo-berlin.jpg etc to parent directory</span>
mv Photo-*.jpg ../
</pre>

</div>

## Executing Programs

Now the last part missing is: How do I execute a program on the command line? Of course, globally installed software can be run by simply executing the command. But local files? They sometimes need execution permission (macOS and linux only)

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># Add execution permission to file on macOS/Linux</span>
chmod +x <FILENAME>

<span style="color: #008800; font-style: italic"># execute a local file</span>
./<FILENAME>
<span style="color: #008800; font-style: italic"># Example: list connected devices with android developer tools</span>
./adb list devices
</pre>

</div>

Beware that the above command sets execution permissions for all users on your computer. If you are managing permissions for a file outside of your personal directory or generally want to learn more about your unix/linux permissions, [tutorialspoint](https://www.tutorialspoint.com/unix/unix-file-permission.htm) explains it well.

## Make it fun to use!

Now I would love to share an easy-to-setup terminal, that is really fun to use. Including bells and whistles!  
First, let‘s get a good terminal Emulator that supports tabs.  
Just like in my browser, I often use multiple Terminal Tabs (e.g. for working in different Git repositories)

*   Windows: [Windows Terminal](https://www.microsoft.com/de-de/p/windows-terminal/9n0dx20hk701?rtc=1)
*   MacOS: [iTerm2](https://www.iterm2.com/)
*   Ubuntu Linux: [Guake](http://guake-project.org/)

Okay. Now that the terminal emulator (the window) is easy to rich and offers tabs, support for ctrl+f/cmd+f text search, copy-paste and more, it‘s time to upgrade what‘s inside of that window.

Meet [Starship](https://starship.rs/).

Starship is a feature-loaded command prompt, which automatically shows you the following information and more without you asking for it:

*   Git Status
*   Current User
*   If the last command returned an error
*   Current directory’s NodeJS/Python/Ruby/Rust/Dotnet/Java/etc version
*   Current Kubernetes/Azure/AWS/etc environment
*   command duration

Just check out the gif on its website. it shows it all.  
As I also like the features oh-my-zsh brings to the table, I use iTerm2+[oh-my-zsh](https://ohmyz.sh/)+[spaceship](https://github.com/denysdovhan/spaceship-prompt), which is very similar to starship but only available for zsh. If you‘re interested, I might go into detail on my personal setup.

## Thefuck (plugin)

Another Plugin I love using is [thefuck](https://github.com/nvbn/thefuck). Yes, that‘s its name. And it does what you think it does: It adds support for writing fuck when you messed up your last command.

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># try to clone the bouncer repo</span>
git clpne git@github.com:BrutalHack/Bouncer.git
<span style="color: #008800; font-style: italic"># => git: 'clpne' is not a git command. See 'git --help'.</span>

<span style="color: #008800; font-style: italic"># The most similar command is</span>
<span style="color: #008800; font-style: italic"># 	clone</span>

<span style="color: #008800; font-style: italic"># correct the previous command</span>
fuck
<span style="color: #008800; font-style: italic"># => git clone git@github.com:BrutalHack/Bouncer.git [enter/↑/↓/ctrl+c]</span>
</pre>

</div>

My most common case: When I create a local git branch and try git push, git says that I must first setup your new branch to track a remote new branch.  
I do not know this command, but instead write fuck, which then suggests the correct command.  
For those of us working for clients, we can change the word to „carp“, „meh“ or something funny.

<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">

<pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-style: italic"># push new "my-branch" to the git repository</span>
git push
<span style="color: #008800; font-style: italic"># => fatal: The current branch new-branch has no upstream branch.</span>
<span style="color: #008800; font-style: italic"># To push the current branch and set the remote as upstream, use</span>
<span style="color: #008800; font-style: italic">#</span>
<span style="color: #008800; font-style: italic">#    git push --set-upstream origin my-branch</span>

<span style="color: #008800; font-style: italic"># correct the previous command</span>
fuck
<span style="color: #008800; font-style: italic"># => git push --set-upstream origin new-branch [enter/↑/↓/ctrl+c]</span>
</pre>

</div>

## Further Reading

If this was a little much at once, no worries.  
You can come back to this article anytime and look up the commands.

If you wanna learn more about your command line, here are some interesting links:

*   [tldp on the Bash Line History (also applies to PowerShell)](https://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x1712.htm)
*   [Ryans Tutorials on Piping (also applies to PowerShell)](https://ryanstutorials.net/linuxtutorial/piping.php)

Did this post help you? Do you still have questions?  
I will be kapping an eye on the comment section below :)