Hack This: Become a Command Line Assassin

One of your operating system's most powerful tools is more accessible than you think.

|
Sep 17 2016, 3:00pm

No matter what kind of cluttered, icon-littered hellscape your filesystem happens to be, take heart that your computer provides a pristine alternate reality in the form of its command line interface. Essentially, this is a direct, minimal way of interacting with your computer, offering a shortcut around all of the clicking and dragging in the form of a small box that takes text-based commands and is mostly mouse-agnostic.

Using the command line is second-nature for me, almost as much so as using the regular old OSX/Windows GUIs. In developing software/programming, we wind up constantly using a lot of tiny utility applications that just don't have graphical frontends, nor do they need them. To interact with these utilities, we use command-line interfaces, either those provided by an operating system—Terminal in OSX or just the command prompt in Windows—or something third-party, like Cygwin.

Why should you the non-hacker care about this particular functionality? For one thing, it's a slight window into how operating systems actually work. Moreover, there are a few fairly routine tasks that can really only be done via command prompt, and, beyond that, a much larger number of small, helpful utilities that you might like to employ in your regular day-today computing, especially those relating to automation.

Let's start small though and run through a few operating system tasks that we'd normally accomplish via the Windows or Mac GUIs—running programs and dealing with files. But first, a general orientation.

0.0) Bash

For our purposes today, the native Windows and Mac command line environments aren't enormously different. But, so I don't say anything very wrong about the default Windows shell, and also because it's pretty useful, you the Windows user should install the Bash shell. Bash is an enormously popular command-line interface (or shell) that comes built into OSX and Linux, and is now offered as a built-in feature in newer Windows 10 versions. If you have a newer Windows 10 version, follow the instructions for activating Bash here. If not, either update or you can download and install Git, which comes with a Bash emulator called Git-Bash.

0.1) What a shell is

It's tempting to think of a command-shell as being somehow closer to your computer's operating system or more integrated into it at the guts-level, but it's really just a program. The shell's operation consists of users entering commands from a predefined set and then turning around and telling the operating system how to do that. Launching a program by clicking an icon will do something similar.

Commands might be issued individually, as in the case of, say, "ls" (which will list of the files in the current directory), or they might be issued via shell scripts, which are just files containing multiple commands arranged such that they perform some more complicated function. The commands recognized by a shell make up a language, which is kind-of/sort-of a programming language, but in a more narrow sense.

The heart of the shell program, like Bash, is a simple loop that executes again and again, waiting for you the user to type something. When it has that input, it takes it and tries to make sense of it. If it's able to make sense of it, the shell will then call a function like "execvp()," which is a Linux system call directing the OS to claim some physical memory and execute a specific program. If it can't make sense of the command, the shell will just return an error.

It's not even very hard to make a shell program, and you could design one to accommodate really an infinite number of subdomains. You could make a shell that only has built-in commands for playing audio files, for example.

1.0) Getting around

So, we all should be running a Bash command-line now. On Mac or Linux, you'll just need to type "bash" and it will switch over, though things will look about the same. A lot of what follows will work with your default OS command prompt, but to ensure things work right and we're all talking about the same thing, Bash is preferred.

When you run a shell, it's important to realize that it's running inside of a specific location within your filesystem. A directory. Your system will have a directory designated as its "home" directory and this is where the shell will start out. I start out under my own named profile within the "Users" directory, which itself lives within the computer's base-level hard-drive directory, which on a Mac just referred to as "/."

A common utility is the aforementioned "ls." Tap this in, hit enter, and the shell will spit back a list of all of the files and directories within the current folder. If somehow you got lost along the way, you can check which folder you happen to be in by running the "pwd" command.

For example:

To change directories, we use the "cd" command followed by a valid destination directory. Valid destinations can be directories contained within the current directory or directories referenced by their absolute path, which is their location in the computer's filesystem relative to the root directory ("/," or "C:/" in Windows, usually). So, in the example above, to get from the current directory into "justkiddingsubdirector" I type "cd justkiddingsubdirector" and I'm there. To get back, however, I can't just type in "cd justkidding" because justkidding isn't contained within justkiddingsubdirector.

Everything is relative. To get to justkidding, I can do "cd /justkidding," which references the directory in relation to the root. I can also do "cd ..," where the two dots are taken to mean the next directory up from the current directory. Here that happens to be justkidding. To then get from justkidding to the root directory, just do the same command again: "cd ..."

By the way, if you're ever confused by a command in Bash, you can type in the "man" command followed by whatever command is problematic. This will bring up a help page (a manual, really) full of details about the mystery command and its usage.

2.0) Running a program

Just type the name of the program into the shell and hit enter. That's it. It will launch as though you'd clicked its icon in the GUI. Generally, you'll need to be in the same directory as the program or script being launched, or you'll need to reference the absolute path to it. For an installed application (on Mac), a normal-ass program like Skype or Microsoft Word, the path will look something like "/usr/local/bin." More often, you'll be running scripts, those microprograms we talked about earlier, which will be wherever you downloaded or created them. The third option are programs that can be called from anywhere, like Python or Bash itself, because they're referenced via system variables. That's a bit beyond the scope of this, but something to be aware of.

Speaking of Python—a Python installation comes with its own Python command prompt. Python is another command interpreter, one that executes the set of commands built into the Python programming language. Again, a command line interpreter is just another program.

For example:

3.0) Command-line hacks

So, let's actually make this thing useful.

3.1) How connected are you?

A utility called netstat will give some pretty granular details about your relationship to the internet at any given time, including every socket currently active or listening for connections. As you can see by invoking the command "netstat -a" your machine is basically network Grand Central. Note here the command-line flag "-a." Flags are a way of specifying a particular usage of a command beyond its defaults. Here, the flag is indicating that we want netstat to output all connections from all connection protocols (TCP and UDP, mostly).

3.2) Quickly create, read, and write to files

Cat is probably one of the most commonly used commands built into Unix-style command shells (a la Bash). It exists to "concatenate and print (display) the content of files," according to its Unix man page. The simplest usage is to run "cat" followed by some filename, like "cat testfile." In this case, it will just output the contents of the file to the Bash window. If that's not useful, you can also cat the contents of one file to another, new file, like so: "cat testfile > testfile1". The ">" is used to redirect the output of the cat to the second file.

Couple of things to notice in the example below. First, I'm using echo to blast some text into a file. All echo does is take whatever comes after it on the command line and print it to what's known as standard output. This is usually just the screen, but it's possible to redirect it to a file, as we're doing below. Also note the usage of ">>." What this does is change the redirect such that it doesn't overwrite what's in the recipient file. It's just appended to the end, which is pretty useful.

At this point, it's important to emphasize that the basic-ness of these commands is ultimately what makes them powerful. As in the example above, they can be combined as sort of atomic elements into bigger and more functional commands. As far as stringing them together goes, the sky's the limit. I like this sort of coding because it tends to feel really "hack-y" in the original sense of term, which is something like: making something work quickly via improvised cleverness. The keywords are "improvised" and "clever." To hack something is to make it work—somehow.

3.3) grep

Speaking of simple-seeming things that are actually enormously powerful: grep. Grep's basic utility is searching files for some specified content. You might invoke it on the command line like so:

grep "some chunk of data" data.txt

To search, say, all of the files in the current directory, you could swap in *.txt for data.txt, which in filesystem-speak means "every possible combination of characters that might appear before .txt."

If the string "some chunk of data" is contained within the file data.txt, grep will output the line it's contained within to the screen. So what? Fair question. It might seem pretty trivial to your average ctrl-f assassin, but there's a whole lot more packed into this command. It's not just that you can wield grep's search capability against many files at once, or that you can just as easily invoke the inverse search—returning every line that doesn't contain the search string—but grep is built around an almost mythical entity known as a regular expression.

Regular expressions, or regex, are used for pattern matching. I don't have to give grep a string of text at all. I can instead give it a pattern, which is described in the language of regex. Maybe I'm scraping a webpage (downloaded and saved as a text file) and want to save only text following this specific HTML tag: " ." Not only that, but I don't want the returned text to include any other tags, so it needs to exclude all of those. I could do all of this processing by creating a regular expression, which is wild, I think.

Unfortunately, Regex can be pretty inscrutable, resulting in maddening chaos like this:

"(?<=^(?=.*\\b(\\w+) \\w+; \\G).*)?(?:\\1 |(\\w+ ))(\\w+; )"

But the ability to describe a really finely tuned search pattern in such a small space is as powerful as it is completely insane. The syntactical insanity of regex is just the cost of doing business. In any case, regex is a bit beyond the scope of this, but, again, know that it exists.

3.4) Say "this is not at all useful"

And it's not, but still sort of fun. Mac has a command called say that will read back in a somewhat uncanny robot voice whatever you tell it to. The subsection heading above is a valid Bash command (on a Mac).

NULL) Settings

Just Google search "command line hacks" or "terminal hacks." There are in existence a billion cheap blog posts about 10 weird tricks for hacking with the command line and nearly all of them contain the same basic batch of system setting modifications that you can do via the command line: show hidden files! change your screenshot save location! add some spaces to something! It's out there, but kind of lame.

4.0) Writing scripts

A final note. As I said before, the command line's power comes from combining commands. A script, a file containing many commands executed in sequence, is very often how this power is wielded. So, let's do that: make a script. A very simple script.

It's going to be a Bash script, which will be executed by the Bash shell. Unix-like shells come with a text editor called Vim or Vi, but it's completely bonkers and could be the subject of like your entire graduate degree. So, just open a regular old text editor, like TextEdit on Mac or Notepad on Windows. Name the file and give it an ".sh" extension. Make the first line of the file the following, which will tell the environment that executes it that the script needs to be run using Bash.

#! /bin/bash

Now, I'm just going to add the same exact stuff we did in 3.4, except it's all going to be in one file. In all, it will look like this.

#! /bin/bash echo "hellow world" > somefile
cat somefile cat somefile > otherfile cat otherfile echo "gd by wrld" >> otherfile cat otherfile

Got it? Save it somewhere and use the command line to navigate to that directory. To run it, enter in the following:

./yourscript.sh

The "./" tells the shell to look in the current directory for the script. It won't run without it. You probably got an error when you did that, saying "permission denied." Yeah, you need to give yourself access to the thing you just created. You can do this by issuing this command and giving yourself read and write permission:

chmod 755 yourscript.sh

And now:

Success!

Anyhow, that's just a taste of shell scripting. You can consider this a prequel to a Hack This I wrote earlier this year on scripting in general and writing Python scripts. If this is at all interesting, make that your next destination.

Read more Hack This.