Conquering The Command Line by Mark Bates
Conquering The Command Line by Mark Bates
Line
Unix and Linux Commands for Developers
Mark Bates
Contents
Foreword
Preface
Acknowledgments
Introduction
Chapter 1 Basics and Navigation
1.1 Home Directory (~)
1.2 Present Working Directory (pwd)
1.3 List Files and Directories (ls)
1.3.1 Listing a Different Directory
1.3.2 Listing All Files (-a)
1.3.3 Long Form Listing (-l)
1.3.4 Human Readable Sizes (-h)
1.3.5 Sorting by Size (-S)
1.3.6 Sorting by Last Modified Time (-t)
1.3.7 Reverse Sort (-r)
1.4 Links (ln)
1.4.1 Hard Links
1.4.2 Forcing a Link (-f)
1.4.3 Symbolic Links (-s)
1.5 Change Directories (cd)
1.5.1 Navigating Up (..)
1.5.2 Navigating to the Home Directory
1.6 Creating Directories (mkdir)
1.6.1 Create Intermediate Directories (-p)
1.6.2 Verbose Output (-v)
1.7 Copying Files (cp)
1.7.1 Copying a Single File
1.7.2 Copying Multiple Files
1.7.3 Verbose Output (-v)
1.7.4 Copying Directories (-R)
1.7.5 Force Overwriting of a File (-f)
1.7.6 Confirm Overwriting of a File (-i)
1.8 Deleting Files (rm)
1.9 Moving Files (mv)
1.10 Input/Output (|, >)
1.10.1 Redirecting Output (|)
1.10.2 Writing to a File (>)
1.10.3 Reading from a File (<)
1.11 Conclusion
Chapter 2 Ack/Ag
2.1 Installation
2.2 The Basics
2.2.1 Regular Expression Searches
2.2.2 Literal Expression Searches
2.3 Listing Files (-l)
2.4 Case Insensitive Searches (-i)
2.5 Scoping to Files (-G)
2.6 Ignoring Paths
2.6.1 The –ignore-dir Flag
2.6.2 VCS Ignore Files (Ag only)
2.6.3 The .agignore File (Ag only)
2.6.4 The .ackrc File (Ack only)
2.7 Searching from Standard Input
2.8 Performance
2.9 Conclusion
Chapter 3 cURL
3.1 Installation
3.2 The Basics
3.3 Following Redirects (-L)
3.4 Downloading Files (-O)
3.4.1 Custom File Names (-o)
3.5 Changing the HTTP Request Method (-X)
3.5.1 Sending Parameters
3.5.2 Passing Data in a Request Body (-d)
3.5.3 Using a File for a Request Body (-d)
3.5.4 Form Parameters (-F)
3.6 Setting Headers (-H)
3.7 Basic HTTP Auth (-u)
3.8 Saving and Sending Cookies/Headers (-D, -b)
3.8.1 Using the Cookie Jar (-c)
3.9 Conclusion
Chapter 4 Find
4.1 The Basics (-name)
4.2 Searching Paths (-path)
4.2.1 Find Only Files or Directories (-type)
4.3 And/Or Expressions (-or)
4.4 Not Matching Query (!, -not)
4.5 Find by Last Modified Time (-mtime)
4.6 Find by File Size (-size)
4.7 Performing Operations (-delete)
4.8 Conclusion
Chapter 5 Grep
5.1 The Basics
5.1.1 Regular Expression Searches
5.1.2 Counting Occurrences (-c)
5.1.3 Displaying Line Numbers (-n)
5.1.4 Case Insensitive Search (-i)
5.2 Searching Multiple Files
5.2.1 Searching Specific Files
5.2.2 Recursive Searching (-R)
5.3 Searching from Standard Input
5.4 Invert Searches (-v)
5.5 Conclusion
Chapter 6 Ps
6.1 The Basics
6.1.1 Columns
6.2 Display User-Oriented Output (u)
6.2.1 Columns
6.3 Display All Processes (-e)
6.4 Display Processes by User (-U)
6.5 Customize Displayed Columns (-O, -L)
6.6 Sorting
6.6.1 Sort by Memory Usage (-m)
6.6.2 Sort by CPU Usage (-r)
6.7 Conclusion
Chapter 7 Sed
7.1 Installation (Mac OS X)
7.2 The Basics (s)
7.2.1 Global Replace
7.2.2 nth Replace
7.3 Saving Files
7.3.1 Editing in Place (-i)
7.3.2 Using Backup Files
7.4 Case Insensitive Searches
7.5 Matching Lines
7.6 Manipulating Matches
7.6.1 Changing Case
7.7 Controlling Output (-n)
7.7.1 Printing Modified Content (p)
7.7.2 Writing Modified Content to a File (w)
7.7.3 Displaying Specific Lines
7.8 Delete Lines (d)
7.9 Running Multiple sed Commands (;)
7.10 Conclusion
Chapter 8 Tar
8.1 The Basics (-c)
8.2 Saving to a File (-f)
8.2.1 Verbose Mode (-v)
8.2.2 Multiple Directories/Files
8.2.3 Building from find (-T)
8.3 Listing Files (-t)
8.4 Appending Files (-r)
8.5 Updating a File (-u)
8.6 Extracting Files (-x)
8.6.1 Extracting a Single File
8.6.2 Extracting to a Different Folder (-C)
8.7 Compressing with gzip (-z)
8.8 Extracting Compressed Files (-z)
8.9 Conclusion
Chapter 9 Extras
9.1 Cal
9.1.1 Display Current Month
9.1.2 Display Current Year
9.1.3 Display an Alternative Year
9.1.4 Display an Alternate Month/Year
9.2 Cat
9.2.1 Read a File
9.2.2 Concatenate Multiple Files
9.2.3 Save Multiple Files to a New File
9.2.4 Display Line Numbers
9.3 Kill
9.3.1 Forcefully Terminate a Process
9.4 Man
9.5 Pbcopy (Mac OS X Only)
9.6 Pbpaste (Mac OS X Only)
9.7 Tail
9.7.1 Display Last n Lines of a File
9.7.2 Reverse Output of a File
9.7.3 Watch a “Live” File
9.7.4 Search “Live” Output
9.8 Tree
9.8.1 Installation
9.8.2 Listing a Directory’s Contents
9.8.3 Limiting the Depth of Listing (-L)
9.8.4 Listing Directories Only (-d)
9.8.5 Listing Another Directory
9.9 Wc
9.9.1 Count Words in a File (-w)
9.9.2 Count Lines in a File (-l)
9.9.3 Piping Input to WC
Foreword
I distinctly remember, as a freshman in college, asking a local guru
how to rename a file in Unix. “It’s mv,” he said “for ‘move’.” To me,
he was a Unix god, and here I was not even knowing mv. Hey, we all
have to start somewhere.
Michael Hartl
Author, The Ruby on Rails Tutorial
Preface
Who is This Book For?
This book is for new developers, experienced developers, and
everyone in between who wants to master Unix and Linux
commands. This book was designed to showcase some of the most
useful commands that a developer can know to help them in their
daily tasks.
Code Examples
For most of the examples in this book we will use the Rails source
code as a way to demonstrate a lot of the commands we will look at.
The source code for Rails can easily be downloaded from GitHub
using Git.
Because Rails is an ever changing code base, your results may vary
from those in the book as the source code changes.
Acknowledgments
Books are not written in a vacuum, and this book was no exception.
It is easy to assume that since there is only one name on the cover
of this book, that there is only person responsible for bringing it all
to fruition - when in fact, this couldn’t be any further from the
truth.
I have a lot of people to thank for helping to get this book in your
hands, yourself included. If I didn’t think people such as yourself
would want to read this book, I wouldn’t have written it, so thank
you so much.
Well, enough gushing - I just hope you enjoy this book, and that it
helps you as much as I hope it will. Enjoy.
Introduction
The story of how this book came to be started in April of 2013 at
RailsConf in Portland, Oregon. At RailsConf I was hanging out with
Michael Hartl, author of the Rails Tutorial. Michael and I had
known each other for a few years through conferences, as well as
both being authors for Addison-Wesley.
I loved writing this book. It wasn’t always easy, no book ever is, but
it was incredibly educational. I found new tools, new flags, and new
options that have radically changed the way I work everyday. I have
found myself referring to this book, while I was writing it. I have
incorporated all of these tools into my daily work flow, and I hope
you do too.
Mark Bates
January, 2014
Chapter 1
Basics and Navigation
It’s important to have a firm grasp on the basics of how to use the
Unix (or Linux) command line. This includes navigating around
directories, copying files, creating files, etc.
The rest of this book will assume you understand what is in this
chapter.
Finding your home directory is incredibly easy. When you first log
into your system you will automatically be placed in your home
directory by default. With this knowledge, you can use the pwd
command (Section 1.2) to get the path of your home directory.
Your home directory will be where your settings files get stored and
where your desktop is kept. The home directory (or subdirectories
under your home directory) is also where you will save documents
and files that are yours and not to be shared with others.
It is quite common to see a tilde (~) in place of the full path for a
home directory. The ~ will expand to be the path of your home
directory when you use commands such as cd (Section 1.5).
$ pwd
Listing 1.2
/Users/markbates/development/unix_commands
In Listing 1.2 you can see the directory I’m currently working in.
For me, it’s the directory that I’m writing this book in.
By default, pwd will list the “logical” path of your current directory.
This means it will treat symlinked paths (see Section 1.4.3) as if
they were the actual paths. For example, my development directory
doesn’t exist under my home folder, /Users/markbates; instead it is
symlinked to a folder inside of /Users/markbates/Dropbox.
If we want to see the actual physical path, with all of the symlinks
resolved, we can use the -P flag.
$ pwd -P
Listing 1.3
/Users/markbates/Dropbox/development/unix_commands
$ ls
Listing 1.4
Applications Calibre Library Desktop Documents Downloads
Dropbox Library Movies Music Pictures
Public Sites development screencasts scripts
tmp
Listing 1.4 shows the list of folders and files in my current directory,
which for me would be my home directory, /Users/markbates. I will
be using my home directory for all of the examples in this section,
unless otherwise noted.
$ ls /usr/local/
Listing 1.5
CONTRIBUTING.md Cellar Frameworks Library README.md
SUPPORTERS.md bin etc foreman go
heroku include lib opt sbin
share texlive var
Listing 1.5 shows the files and directories inside of the /usr/local
directory, without having to leave the current directory that I am in.
So far we have seen all of the “visible” files and directories listed,
however, it is common on Unix and Linux based machines to have
“invisible”, or “hidden”, files that are prefixed with a “.” (dot).
Using the -a flag we can see both “visible” and “hidden” files and
directories.
$ ls -a
Listing 1.6
. .Trash .bashrc .ctags
.el4r .erlang.cookie .go .mplayer
.psql_history .rvm .swt .zshrc
Dropbox Sites .. .Xauthority
.cache .cups .el4rrc.rb .gem
.guard_history .netrc .railsrc .rvmrc
.vim Applications Library development
.CFUserTextEncoding .adobe .cisco .dbshell
.emacs .gemrc .gvimrc .node-gyp
.redis-commander .scala_history .viminfo Calibre Library
Movies screencasts .DS_Store .anyconnect
.cloud66 .dropbox .emacs.d .git-completion.sh
.heroku .npm .rediscli_history .softcover
.vimrc Desktop Music scripts
.MakeMKV .bash_history .codeintel .dvdcss
.ember .gitconfig .inkscape-etc .pry_history
.rnd .ssh .z Documents
Pictures tmp .NERDTreeBookmarks .bash_profile
.config .editedhistory .ember-data .gnome2
.irb-history .pryrc .rspec .subversion
.zlogin Downloads Public
Listing 1.6 now shows significantly more files and directories than
Listing 1.4 because the -a flag is including all of the “hidden” files,
as well as the “visible” ones.
$ ls -l
Listing 1.7
drwxr-xr-x 16 markbates staff 544 Aug 19 13:58 Applications
drwxr-xr-x 5 markbates staff 170 Dec 6 16:20 Calibre Library
lrwxr-xr-x 1 markbates staff 33 Jul 26 2012 Desktop ->
/Users/markbates/Dropbox/Desktop/
lrwxr-xr-x 1 markbates staff 35 Jul 26 2012 Documents ->
/Users/markbates/Dropbox/Documents/
drwx------+ 140 markbates staff 4760 Dec 16 13:44 Downloads
drwx------@ 24 markbates staff 816 Dec 15 17:24 Dropbox
drwx------@ 66 markbates staff 2244 Oct 23 08:29 Library
drwx------+ 5 markbates staff 170 Sep 15 18:06 Movies
drwx------+ 6 markbates staff 204 Mar 5 2013 Music
drwx------+ 10 markbates staff 340 Jul 31 18:20 Pictures
drwxr-xr-x+ 4 markbates staff 136 Mar 5 2013 Public
drwxr-xr-x+ 3 markbates staff 102 Mar 5 2013 Sites
lrwxr-xr-x 1 markbates staff 37 Jul 26 2012 development ->
/Users/markbates/Dropbox/development/
lrwxr-xr-x 1 markbates staff 37 Jun 1 2013 screencasts ->
/Users/markbates/Dropbox/screencasts/
lrwxr-xr-x 1 markbates staff 33 Jul 26 2012 scripts ->
/Users/markbates/Dropbox/scripts/
drwxr-xr-x 19 markbates staff 646 Dec 6 16:07 tmp
$ ls -lh
Listing 1.8
drwxr-xr-x 16 markbates staff 544B Aug 19 13:58 Applications
drwxr-xr-x 5 markbates staff 170B Dec 6 16:20 Calibre Library
lrwxr-xr-x 1 markbates staff 33B Jul 26 2012 Desktop ->
/Users/markbates/Dropbox/Desktop/
lrwxr-xr-x 1 markbates staff 35B Jul 26 2012 Documents ->
/Users/markbates/Dropbox/Documents/
drwx------+ 140 markbates staff 4.6K Dec 16 13:44 Downloads
drwx------@ 24 markbates staff 816B Dec 15 17:24 Dropbox
drwx------@ 66 markbates staff 2.2K Oct 23 08:29 Library
drwx------+ 5 markbates staff 170B Sep 15 18:06 Movies
drwx------+ 6 markbates staff 204B Mar 5 2013 Music
drwx------+ 10 markbates staff 340B Jul 31 18:20 Pictures
drwxr-xr-x+ 4 markbates staff 136B Mar 5 2013 Public
drwxr-xr-x+ 3 markbates staff 102B Mar 5 2013 Sites
lrwxr-xr-x 1 markbates staff 37B Jul 26 2012 development ->
/Users/markbates/Dropbox/development/
lrwxr-xr-x 1 markbates staff 37B Jun 1 2013 screencasts ->
/Users/markbates/Dropbox/screencasts/
lrwxr-xr-x 1 markbates staff 33B Jul 26 2012 scripts ->
/Users/markbates/Dropbox/scripts/
drwxr-xr-x 19 markbates staff 646B Dec 6 16:07 tmp
Another useful flag we can use with ls is -S, which will sort the
results of ls by file size, instead of the default sorting by name.
$ ls -lhS
Listing 1.9
drwx------+ 140 markbates staff 4.6K Dec 16 13:44 Downloads
drwx------@ 66 markbates staff 2.2K Oct 23 08:29 Library
drwx------@ 24 markbates staff 816B Dec 15 17:24 Dropbox
drwxr-xr-x 19 markbates staff 646B Dec 6 16:07 tmp
drwxr-xr-x 16 markbates staff 544B Aug 19 13:58 Applications
drwx------+ 10 markbates staff 340B Jul 31 18:20 Pictures
drwx------+ 6 markbates staff 204B Mar 5 2013 Music
drwxr-xr-x 5 markbates staff 170B Dec 6 16:20 Calibre Library
drwx------+ 5 markbates staff 170B Sep 15 18:06 Movies
drwxr-xr-x+ 4 markbates staff 136B Mar 5 2013 Public
drwxr-xr-x+ 3 markbates staff 102B Mar 5 2013 Sites
lrwxr-xr-x 1 markbates staff 37B Jul 26 2012 development ->
/Users/markbates/Dropbox/development/
lrwxr-xr-x 1 markbates staff 37B Jun 1 2013 screencasts ->
/Users/markbates/Dropbox/screencasts/
lrwxr-xr-x 1 markbates staff 35B Jul 26 2012 Documents ->
/Users/markbates/Dropbox/Documents/
lrwxr-xr-x 1 markbates staff 33B Jul 26 2012 Desktop ->
/Users/markbates/Dropbox/Desktop/
lrwxr-xr-x 1 markbates staff 33B Jul 26 2012 scripts ->
/Users/markbates/Dropbox/scripts/
In Listing 1.9 the results of ls are displayed with the largest files at
the top, and the smallest files at the bottom.
1.3.6 Sorting by Last Modified Time (-t)
$ ls -lt
Listing 1.10
drwx------+ 140 markbates staff 4760 Dec 16 13:44 Downloads
drwx------@ 24 markbates staff 816 Dec 15 17:24 Dropbox
drwxr-xr-x 5 markbates staff 170 Dec 6 16:20 Calibre Library
drwxr-xr-x 19 markbates staff 646 Dec 6 16:07 tmp
drwx------@ 66 markbates staff 2244 Oct 23 08:29 Library
drwx------+ 5 markbates staff 170 Sep 15 18:06 Movies
drwxr-xr-x 16 markbates staff 544 Aug 19 13:58 Applications
drwx------+ 10 markbates staff 340 Jul 31 18:20 Pictures
lrwxr-xr-x 1 markbates staff 37 Jun 1 2013 screencasts ->
/Users/markbates/Dropbox/screencasts/
drwx------+ 6 markbates staff 204 Mar 5 2013 Music
drwxr-xr-x+ 4 markbates staff 136 Mar 5 2013 Public
drwxr-xr-x+ 3 markbates staff 102 Mar 5 2013 Sites
lrwxr-xr-x 1 markbates staff 33 Jul 26 2012 scripts ->
/Users/markbates/Dropbox/scripts/
lrwxr-xr-x 1 markbates staff 35 Jul 26 2012 Documents ->
/Users/markbates/Dropbox/Documents/
lrwxr-xr-x 1 markbates staff 33 Jul 26 2012 Desktop ->
/Users/markbates/Dropbox/Desktop/
lrwxr-xr-x 1 markbates staff 37 Jul 26 2012 development ->
/Users/markbates/Dropbox/development/
When you are listing a directory that contains many files, sorting
with ls is a great way to help quickly find the files or directories you
are looking for. By default, ls sorts all of its results alphabetically.
We also learned how to sort results by size (Section 1.3.5) and by
last modified time (Section 1.3.6).
Listing 1.11
drwxr-xr-x 19 markbates staff 646 Dec 6 16:07 tmp
lrwxr-xr-x 1 markbates staff 33 Jul 26 2012 scripts ->
/Users/markbates/Dropbox/scripts/
lrwxr-xr-x 1 markbates staff 37 Jun 1 2013 screencasts ->
/Users/markbates/Dropbox/screencasts/
lrwxr-xr-x 1 markbates staff 37 Jul 26 2012 development ->
/Users/markbates/Dropbox/development/
drwxr-xr-x+ 3 markbates staff 102 Mar 5 2013 Sites
drwxr-xr-x+ 4 markbates staff 136 Mar 5 2013 Public
drwx------+ 10 markbates staff 340 Jul 31 18:20 Pictures
drwx------+ 6 markbates staff 204 Mar 5 2013 Music
drwx------+ 5 markbates staff 170 Sep 15 18:06 Movies
drwx------@ 66 markbates staff 2244 Oct 23 08:29 Library
drwx------@ 24 markbates staff 816 Dec 15 17:24 Dropbox
drwx------+ 140 markbates staff 4760 Dec 16 13:44 Downloads
lrwxr-xr-x 1 markbates staff 35 Jul 26 2012 Documents ->
/Users/markbates/Dropbox/Documents/
lrwxr-xr-x 1 markbates staff 33 Jul 26 2012 Desktop ->
/Users/markbates/Dropbox/Desktop/
drwxr-xr-x 5 markbates staff 170 Dec 6 16:20 Calibre Library
drwxr-xr-x 16 markbates staff 544 Aug 19 13:58 Applications
In Listing 1.11 we can see that default sort of ls, alphabetically, has
now been reversed with tmp at the top of the list, and Applications
at the bottom.
We can also use the -r flag with other options to reverse their sort
order. For example, ls -lSr will list the files by size with smaller
files listed first.
Hard links create an identical copy of the linked file on disk, that
gets updated automatically as the source file gets updated. That
means if the content of the source is changed, so will the target file.
$ ln a.txt b.txt
Listing 1.12: $ ls -l
-rw-r--r-- 2 markbates staff 12 Dec 17 16:46 a.txt
-rw-r--r-- 2 markbates staff 12 Dec 17 16:46 b.txt
Listing 1.12 shows the newly created b.txt has all of the same
properties as the a.txt file.
An important thing to note about hard links is that they only work
on the current file system. You can not create a hard link to a file on
a different file system. To do that you need to use symbolic links,
Section 1.4.3.
While the content of the source and target files are linked, if the
source file gets deleted, the target file will continue to live as an
independent file, despite the severed link.
$ rm a.txt
Listing 1.13: $ ls -l
-rw-r--r-- 1 markbates staff 12 Dec 17 17:01 b.txt
In Listing 1.13 we can see that the b.txt file still exists, despite the
target file having been deleted.
If we were to use the cat tool from Chapter 9 Section 9.2, we can see
that the contents of b.txt are still intact.
$ cat b.txt
Listing 1.14
Hello World
1.4.2 Forcing a Link (-f)
If the source file already exists you will get an error, like that in
Listing 1.15.
$ ln a.txt b.txt
Listing 1.15
ln: b.txt: File exists
To fix the error in Listing 1.15 you can pass the -f flag to force the
link.
$ ln -f a.txt b.txt
We have seen that the default type of link that gets created when
using ln is that of a hard link. Unfortunately hard links do not work
for directories. To create a link to a directory, we can use the -s flag
to create a symbolic link. This can also be used for linking to files as
well, not just directories.
$ ln -s a.txt b.txt
Listing 1.16: $ ls -l
-rw-r--r-- 1 markbates staff 12 Dec 17 17:01 a.txt
lrwxr-xr-x 1 markbates staff 5 Dec 17 17:12 b.txt -> a.txt
Notice that the file timestamps and size are identical in Listing 1.17
with the hard link, but they are different in Listing 1.18 for the
symbolic link. The reason for the difference is that with the
symbolic link the operating system creates a new, small file that
points to the target file or directory.
$ cd ~/Documents
$ cd ..
When you are in a directory and want to navigate back to your home
directory, you can call cd without any arguments.
$ cd
$ mkdir foo
Listing 1.21: $ ls -l
drwxr-xr-x 2 markbates staff 68 Dec 18 13:20 foo
$ mkdir -p a/b/c
The mkdir command supports a verbose mode flag, -v. Adding the -
v flag will print the results of mkdir to the console.
$ mkdir -v a
Listing 1.23
mkdir: created directory 'a'
Using the -v flag can provide useful reporting when writing scripts
that will execute a lot of commands for you.
$ cp a.txt b.txt
Listing 1.24: $ ls -l
-rw-r--r-- 1 markbates staff 0 Dec 18 13:34 a.txt
-rw-r--r-- 1 markbates staff 0 Dec 18 13:41 b.txt
cp will allows you to list several files you would like to copy. When
you do this, however, the last argument must be a directory, and the
original file names of the source files will be used as the names of
the new files in the target directory.
$ cp *.txt foo
The cp command will print verbose output regarding the files that
were copied using the -v flag.
$ cp -v a.txt b.txt
Listing 1.27
a.txt -> b.txt
$ cp foo bar
Listing 1.28
cp: foo is a directory (not copied).
To fix the error in Listing 1.28, we can use the -R flag to recursively
copy the directory’s contents to the new directory.
Listing 1.29
foo -> bar
foo/a.txt -> bar/a.txt
foo/b.txt -> bar/b.txt
foo/c.txt -> bar/c.txt
Using the verbose flag, -v, we can see in Listing 1.29 all of the files
from the source directory, foo, have been copied to the target
directory, bar.
In Listing 1.30 we can see that we have two files, a.txt and b.txt.
$ ls -l
Listing 1.30
-rw-r--r-- 1 markbates staff 0 Dec 18 13:58 a.txt
-rw-r--r-- 1 root staff 6 Dec 18 14:55 b.txt
When looking at Listing 1.30 we can see that the two files listed are
owned by two different users. The first file, a.txt, is owned by user
markbates, while the second file is owned by root.
$ cp a.txt b.txt
Listing 1.31
cp: b.txt: Permission denied
$ cp -f a.txt b.txt
Listing 1.32: $ ls -l
-rw-r--r-- 1 markbates staff 0 Dec 18 13:58 a.txt
-rw-r--r-- 1 markbates staff 0 Dec 18 14:57 b.txt
When you are about to copy over several files at once, and some of
the target files already exist, it may be beneficial to confirm that you
do in fact want to copy the source file and replace the target file.
$ cp -i a.txt b.txt
Listing 1.33
overwrite b.txt? (y/n [n])
$ rm -v a.txt
Listing 1.34
a.txt
Listing 1.34 uses the -v flag to list files that were deleted using the
rm command.
$ mv -v a.txt b.txt
Listing 1.35
a.txt -> b.txt
We can achieve the same effect from Listing 1.35 by using the cp
and rm commands. This can be useful when trying to move a file
across file systems, as the mv command doesn’t support that.
$ cp a.txt b.txt
$ rm a.txt
Listing 1.36: $ ls -l
-rw-r--r-- 1 markbates staff 0 Dec 18 16:20 b.txt
$ ls -a ~ | grep _
Listing 1.37
.DS_Store
.bash_history
.bash_profile
.guard_history
.pry_history
.psql_history
.rediscli_history
.scala_history
Listing 1.38
.DS-Store
.bash-history
.bash-profile
.guard-history
.pry-history
.psql-history
.rediscli-history
.scala-history
Listing 1.38 shows the result of chaining together the ls, grep, and
sed commands using the | operator.
In Section 1.10.2 we saw that we can use > to write data to a file. If
we instead wanted to read data from a file, we can use <.
1.11 Conclusion
In this chapter we covered the basics of the command line, from
how to navigate between directories, to how to move, delete, or copy
files, and more.
Hopefully this chapter has provided you with the solid footing that
you’ll need to conquer the command line. The commands in this
chapter will become second nature to you over time, as you’ll use
them continuously each day.
Chapter 2
Ack/Ag
Searching large code bases is something that most of us do on a
daily basis. Whether it be to refactor some code, or to simply find
where a variable, class, or method has been implemented. Good
searching tools are the lifeblood of development, and bad searching
tools can make our jobs more difficult than they need be.
In this chapter, we’ll look at two tools that can help make searching
a large number of files fast and easy. Those tools are Ack and Ag.
Ack and Ag are 99% feature compatible with each other, so you can
use them interchangeably.
We’ll want a sizable code base to search through to show the power
of ack/ag, so we’ll be using the Rails source code, as mentioned in
the Preface.
2.1 Installation
There’s a very good chance that you already have Ack installed on
your machine already, but it is nice to be up-to-date with the latest
version.
If you are on a Mac, the best and easiest way to install either Ack or
Ag is using Homebrew.
$ ag DHH
The result of our search should look something like Listing 2.11 :
Listing 2.1
actionview/lib/action_view/helpers/atom_feed_helper.rb
43: # author.name("DHH")
76: # author.name("DHH")
actionview/test/template/atom_feed_helper_test.rb
25: author.name("DHH")
42: author.name("DHH")
59: author.name("DHH")
71: author.name("DHH")
95: author.name("DHH")
113: author.name("DHH")
131: author.name("DHH")
149: author.name("DHH")
171: author.name("DHH")
191: author.name("DHH")
279: assert_select "author name", :text => "DHH"
activerecord/CHANGELOG.md
58: *DHH*
67: *DHH*
92: *DHH*
activerecord/lib/active_record/relation.rb
100: # users = User.where(name: 'DHH')
101: # user = users.new # => #<User id: nil, name: "DHH", created_at: ...
activerecord/lib/active_record/relation/query_methods.rb
685: # users = users.create_with(name: 'DHH')
686: # users.new.name # => 'DHH'
activerecord/test/cases/xml_serialization_test.rb
388: assert_no_match %r{^ <copyright>DHH</copyright>}, xml
389: assert_match %r{^ {6}<copyright>DHH</copyright>}, xml
activesupport/CHANGELOG.md
30: *DHH*
98: *DHH*
122: *DHH*
guides/source/caching_with_rails.md
33:INFO: Page Caching has been removed from Rails 4. ...
39:INFO: Action Caching has been removed from Rails 4. ...
guides/source/migrations.md
109:`YYYYMMDDHHMMSS_create_products.rb`, that is to say a UTC timestamp
227:`db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb` file.
As you can see, the first argument we pass in is the search term we
want to find in our directory of files. By default, this query is run
recursively against the current directory.
Listing 2.2
guides/source/caching_with_rails.md
33:INFO: Page Caching has been removed from Rails 4. ...
39:INFO: Action Caching has been removed from Rails 4. ...
guides/source/migrations.md
109:`YYYYMMDDHHMMSS_create_products.rb`, that is to say a UTC timestamp
227:`db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb` file.
Let’s search for any occurrence of the word readme at the end of a
line.
$ ag readme$
Listing 2.3
railties/lib/rails/generators/rails/app/app_generator.rb
40: def readme
railties/lib/rails/generators/rails/plugin/plugin_generator.rb
32: def readme
railties/test/generators/actions_test.rb
203: def test_readme
2.2.2 Literal Expression Searches
$ ag .rb railties/CHANGELOG.md
Listing 2.4
70:* Rename `commands/plugin_new.rb` to `commands/plugin.rb` ...
78:* Omit turbolinks configuration completely on skip_javascript ...
103:* Changes repetitive th tags to use colspan attribute ...
Listing 2.4 lists the results3 of our query. Since Ag matches the
pattern as a regular expression, our results includes some things we
don’t want, such as turbolinks.
To fix this we can change our query to the use -Q flag. This will
search for the exact pattern, .rb, in the file.
$ ag -Q .rb railties/CHANGELOG.md
Listing 2.5
70:* Rename `commands/plugin_new.rb` to `commands/plugin.rb` ...
$ ag DHH -l
The result set is now presented as just a list of files, Listing 2.6.
Listing 2.6
actionview/lib/action_view/helpers/atom_feed_helper.rb
actionview/test/template/atom_feed_helper_test.rb
activerecord/CHANGELOG.md
activerecord/lib/active_record/relation.rb
activerecord/lib/active_record/relation/query_methods.rb
activerecord/test/cases/xml_serialization_test.rb
activesupport/CHANGELOG.md
guides/source/caching_with_rails.md
guides/source/migrations.md
To demonstrate this, let’s change our search query. This time, we’ll
search for the term readme. We’ll also use the -l flag that we
learned about earlier to keep our result set easier to read.
$ ag readme -l
Listing 2.7
guides/code/getting_started/Gemfile
guides/source/asset_pipeline.md
guides/source/generators.md
guides/source/getting_started.md
railties/lib/rails/generators/actions.rb
railties/lib/rails/generators/app_base.rb
railties/lib/rails/generators/rails/app/app_generator.rb
railties/lib/rails/generators/rails/plugin/plugin_generator.rb
railties/test/generators/actions_test.rb
Now let’s add the -i flag to our query and see how that changes our
result set.
$ ag readme -l -i
Listing 2.8 shows the results of adding the -i flag to our search
query.
Listing 2.8
actionmailer/actionmailer.gemspec
actionpack/actionpack.gemspec
actionpack/test/controller/action_pack_assertions_test.rb
actionview/actionview.gemspec
activemodel/activemodel.gemspec
activerecord/activerecord.gemspec
activerecord/lib/active_record/base.rb
activesupport/activesupport.gemspec
guides/code/getting_started/Gemfile
guides/code/getting_started/README.rdoc
guides/source/command_line.md
guides/source/asset_pipeline.md
guides/source/generators.md
guides/source/getting_started.md
guides/source/plugins.md
guides/source/rails_application_templates.md
guides/source/working_with_javascript_in_rails.md
rails.gemspec
railties/lib/rails/api/task.rb
railties/lib/rails/generators/actions.rb
railties/lib/rails/generators/app_base.rb
railties/lib/rails/generators/rails/app/app_generator.rb
railties/lib/rails/generators/rails/app/templates/README.rdoc
railties/lib/rails/generators/rails/app/USAGE
railties/lib/rails/generators/rails/plugin/plugin_generator.rb
railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
railties/lib/rails/generators/rails/plugin/templates/Rakefile
railties/lib/rails/generators/rails/plugin/USAGE
railties/lib/rails/tasks/documentation.rake
railties/railties.gemspec
railties/RDOC_MAIN.rdoc
railties/test/generators/actions_test.rb
railties/test/generators/app_generator_test.rb
railties/test/generators/plugin_generator_test.rb
README.md
As you can see, ag returns significantly more files now using a case
insensitive search.
$ ag readme -l -G action
Listing 2.9
railties/lib/rails/generators/actions.rb
railties/test/generators/actions_test.rb
Let’s modify our query slightly and search for files that end with ec.
$ ag readme -l -i -G ec
As Listing 2.10 shows us, we don’t quite have our query tuned the
way we want it, since it also returned files like
activerecord/lib/active_record/base.rb, matching the ec in
record.
Listing 2.10
actionmailer/actionmailer.gemspec
actionpack/actionpack.gemspec
actionview/actionview.gemspec
activemodel/activemodel.gemspec
activerecord/activerecord.gemspec
activerecord/lib/active_record/base.rb
activesupport/activesupport.gemspec
rails.gemspec
railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
railties/railties.gemspec
Instead of finding files that end in ec, the search results are showing
us files that contain ec anywhere in the name. How do we fix our
query to get back the results we want?
$ ag readme -l -i -G ec$
Listing 2.11
actionmailer/actionmailer.gemspec
actionpack/actionpack.gemspec
actionview/actionview.gemspec
activemodel/activemodel.gemspec
activerecord/activerecord.gemspec
activesupport/activesupport.gemspec
rails.gemspec
railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
railties/railties.gemspec
As you can see in Listing 2.11 our search results now only contain
files that end with ec. Success!
$ ag readme -l
Listing 2.12
guides/code/getting_started/Gemfile
guides/source/asset_pipeline.md
guides/source/generators.md
guides/source/getting_started.md
railties/lib/rails/generators/actions.rb
railties/lib/rails/generators/app_base.rb
railties/lib/rails/generators/rails/app/app_generator.rb
railties/lib/rails/generators/rails/plugin/plugin_generator.rb
railties/test/generators/actions_test.rb
$ ag readme -l --ignore-dir=railties/lib
Listing 2.13 shows that we have successfully filtered out those files.
All results from files located in that directory will be omitted.
Listing 2.13
guides/code/getting_started/Gemfile
guides/source/asset_pipeline.md
guides/source/generators.md
guides/source/getting_started.md
railties/test/generators/actions_test.rb
See Listing 2.14 for the results of using multiple ignore flags.
Listing 2.14
guides/source/asset_pipeline.md
guides/source/generators.md
guides/source/getting_started.md
railties/test/generators/actions_test.rb
Despite its name, the –ignore-dir flag will also let us filter out
particular files, not just directories.
$ ag readme -l --ignore-dir="*.rb"
Listing 2.15
guides/code/getting_started/Gemfile
guides/source/asset_pipeline.md
guides/source/generators.md
guides/source/getting_started.md
In Listing 2.15 we, again searched for the term readme, except this
time we ignored all files that matched the pattern *.rb.
Listing 2.16
debug.log
.Gemfile
/.bundle
/.ruby-version
/Gemfile.lock
pkg
/dist
/doc/rdoc
/*/doc
/*/test/tmp
/activerecord/sqlnet.log
/activemodel/test/fixtures/fixture_database.sqlite3
/activesupport/test/fixtures/isolation_test
/railties/test/500.html
/railties/test/fixtures/tmp
/railties/test/initializer/root/log
/railties/doc
/railties/tmp
/guides/output
railties/lib
guides/code
Now if we were to run the same query, but without the –ignore-dir
flags, as shown in Listing 2.17, ag would return the same results as
Listing 2.14, but with significantly less typing.
$ ag readme -l
Listing 2.17
guides/source/asset_pipeline.md
guides/source/generators.md
guides/source/getting_started.md
railties/test/generators/actions_test.rb
Of course, there might be times when you don’t want to use this
feature. Thankfully, there is a flag we can pass to Ag to tell it to
ignore any VCS files.
$ ag readme -l --skip-vcs-ignores
The .agignore file specifies ignore paths for Ag, and works
independently of any VCS file.
Listing 2.19
railties/lib
guides/code
This lets us keep our VCS ignore files focused on what can/can’t be
committed to source control, while still being able to give Ag
direction as to which paths we want to exclude from search.
The .ackrc is identical in nature to the .agignore file, but is for use
with Ack, instead of Ag.
2.7 Searching from Standard
Input
Both Ack and Ag will expect standard input as a source for
searching. This means we don’t need to just search files, but we can
use other commands to provide the data we’ll search over.
$ ps -e | ag forego
Listing 2.20
58627 ttys005 0:00.91 forego start -p 3000
This ability is incredibly useful, not just for finding things such as
running processes, but for reading file input from a command such
as cat, Chapter 9 Section 9.2, amongst other uses.
2.8 Performance
Earlier in this chapter I mentioned how I prefer Ag over Ack
because of its speed. Let me demonstrate what I mean. Let’s
benchmark two pretty simple queries using the two different tools.
real 0m0.981s
user 0m0.828s
sys 0m0.149s
$ time ag DHH
real 0m0.086s
user 0m0.059s
sys 0m0.142s
2.9 Conclusion
Well, that’s a good look at what Ack and Ag can do to help us quickly
search through large code bases.
Both tools will give you a print out of their full features if you
simply call them without any parameters.
1. This output has been truncated to better fit the format of this book. ↑
2. This output has been truncated to better fit the format of this book. ↑
3. This output has been truncated to better fit the format of this book. ↑
4. This output has been truncated to better fit the format of this book. ↑
5. In Ack the -g flag is the equivalent of the -G flag in Ag, so just switch out the case of
the flag accordingly. ↑
Chapter 3
cURL
cURL is easily one of the most powerful tools in a developer’s
toolkit, as well as one of the most complex ones. It ships with a
dizzying array of options and features, most of which you will not
need on a daily basis.
cURL is a tool for working with URLs. cURL lets us query a URL
from the command line. It lets us post form data, FTP to a server,
and much, much more. One of the places that cURL comes in
handy most often is working with APIs. With cURL we can try out
new APIs simply, with just the command line, with no need for
installing, or writing complex wrappers around the API.
In this chapter, we will look at how we can use cURL to work with
remote URLs. We’ll also learn about the flags that will give us the
most bang for our buck in an average day.
3.1 Installation
There’s a very good chance that you already have cURL installed on
your machine, but it is nice to be up-to-date with the latest version.
If you are on a Mac, the best and easiest way to install cURL is using
Homebrew.
$ curl quiet-waters-1228.herokuapp.com/hello
As you can see in Listing 3.1, cURL prints the response of the web
page to the console.
Listing 3.1
Hello, World!
Thank you for cURLing me!
$ curl -i quiet-waters-1228.herokuapp.com/hello
Listing 3.2
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: text/html; charset=utf-8
Etag: "a0bb15ce430e40738d857e3e7dfe0de7"
Server: thin 1.6.1 codename Death Proof
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: d605f89d-bffc-4983-8ca4-8ac2b77c7b8d
X-Runtime: 0.002568
X-Ua-Compatible: chrome=1
X-Xss-Protection: 1; mode=block
transfer-encoding: chunked
Connection: keep-alive
Hello, World!
Thank you for cURLing me!
$ curl -i quiet-waters-1228.herokuapp.com/redirectme
Listing 3.3
HTTP/1.1 302 Moved Temporarily
Cache-Control: no-cache
Content-Type: text/html; charset=utf-8
Location: http://quiet-waters-1228.herokuapp.com/hello
Server: thin 1.6.1 codename Death Proof
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: e9785070-173c-4e8a-bbf5-1686806cbd6b
X-Runtime: 0.007276
X-Ua-Compatible: chrome=1
X-Xss-Protection: 1; mode=block
transfer-encoding: chunked
Connection: keep-alive
<html>
<body>
You are being
<a href="http://quiet-waters-1228.herokuapp.com/hello">redirected</a>.
</body>
</html>
$ curl -L quiet-waters-1228.herokuapp.com/redirectme
Using the -L flag we should now get the same response we did in
Listing 3.1.
$ curl http://quiet-waters-1228.herokuapp.com/assets/image.jpg
Listing 3.4
??JFIF,,??tExifII*
????(1?2?i??? NIKONE950,,Adobe Photoshop 7.02002:04:25 15:29:28??????"?'
Listing 3.4 shows the first two lines from a lot of gibberish that
represents a binary image file. However if we add the -O flag to the
request, the results will be saved into a file named image.jpg.
$ curl -O http://quiet-waters-1228.herokuapp.com/assets/image.jpg
Listing 3.5 and Listing 3.6 show the file downloading, and then a
confirmation of the file saved to disk.
Listing 3.5
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 413k 100 413k 0 0 306k 0 0:00:01 0:00:01 --:--:-- 306k
As Listing 3.6 shows us, the file is downloaded from the server to
the current working directory using the same name as the file on
the server. Section 3.4.1 will show us how we can change the name
of this file.
More often than not, we can use the name of the file from the
server as the name of the file that we download to disk. However, in
this example case the name image.jpg leaves a lot to be desired. We
don’t know what it is an image of.
We can solve this problem in several different ways. The first way is
to use the mv command to rename the file after we’ve downloaded
it. Another way is to use the -o flag to give cURL a file name to save
the file to.
Listing 3.7 shows that the file has now been downloaded using the
custom file name that we specified using the -o flag.
Let’s make a simple POST request to an “echo” server that will print
out any parameters we send to it.
Listing 3.8
<!DOCTYPE html>
<html>
<head>
<title>Unix and Linux Commands for Developers</title>
<link href="/assets/application.css" media="all" rel="stylesheet" />
<script src="/assets/application.js"></script>
</head>
<body>
<p>
<strong>url:</strong>
<span>
http://quiet-waters-1228.herokuapp.com/echo
</span>
</p>
<p>
<strong>method:</strong>
<span>
POST
</span>
</p>
</body>
</html>
Let’s make the same request again, only this time using the PUT
request method.
Listing 3.9 confirms that we did indeed change the request method
from POST to PUT.
Listing 3.9
<!DOCTYPE html>
<html>
<head>
<title>Unix and Linux Commands for Developers</title>
<link href="/assets/application.css" media="all" rel="stylesheet" />
<script src="/assets/application.js"></script>
</head>
<body>
<p>
<strong>url:</strong>
<span>
http://quiet-waters-1228.herokuapp.com/echo
</span>
</p>
<p>
<strong>method:</strong>
<span>
PUT
</span>
</p>
</body>
</html>
Depending on your request type (in our case this was HTTP), the -X
flag changes the request method appropriately. For example, with
an FTP request the -X flag will allow you to change the request type
from LIST to another request method.
Listing 3.10 shows that the query string parameters are parsed
correctly by the echo server.
Listing 3.10
<!DOCTYPE html>
<html>
<head>
<title>Unix and Linux Commands for Developers</title>
<link href="/assets/application.css" media="all" rel="stylesheet" />
<script src="/assets/application.js"></script>
</head>
<body>
<p>
<strong>url:</strong>
<span>
http://quiet-waters-1228.herokuapp.com/echo?fname=Mark&lname=Bates
</span>
</p>
<p>
<strong>parameters:</strong>
<span>
{"fname"=>"Mark", "lname"=>"Bates"}
</span>
</p>
<p>
<strong>method:</strong>
<span>
POST
</span>
</p>
</body>
</html>
Passing query string parameters will work with any request type,
not just POST. This is the simplest, and easiest, way to pass data to
the server in a cURL request, but not the only way.
Instead of passing the data via query string parameters, let’s use the
-d flag instead.
$ curl -X POST -d "fname=Mark&lname=Bates" quiet-waters-1228.herokuapp.com/echo
As we can see in Listing 3.11, the echo server reads the body and
converts it into parameters, just as if we had used query string
parameters.
Listing 3.11
<!DOCTYPE html>
<html>
<head>
<title>Unix and Linux Commands for Developers</title>
<link href="/assets/application.css" media="all" rel="stylesheet" />
<script src="/assets/application.js"></script>
</head>
<body>
<p>
<strong>url:</strong>
<span>
http://quiet-waters-1228.herokuapp.com/echo
</span>
</p>
<p>
<strong>parameters:</strong>
<span>
{"fname"=>"Mark", "lname"=>"Bates"}
</span>
</p>
<p>
<strong>method:</strong>
<span>
POST
</span>
</p>
<p>
<strong>body:</strong>
<span>
fname=Mark&lname=Bates
</span>
</p>
</body>
</html>
We can also see in Listing 3.11 that the echo server now displays a
bodyattribute to us. This proves that the data is in fact coming as a
request body, and not just basic parameters.
We can make this more interesting by passing JSON via the -d flag.
Listing 3.12
<!DOCTYPE html>
<html>
<head>
<title>Unix and Linux Commands for Developers</title>
<link href="/assets/application.css" media="all" rel="stylesheet" />
<script src="/assets/application.js"></script>
</head>
<body>
<p>
<strong>url:</strong>
<span>
http://quiet-waters-1228.herokuapp.com/echo
</span>
</p>
<p>
<strong>method:</strong>
<span>
POST
</span>
</p>
<p>
<strong>body:</strong>
<span>
{"name"=>"Mark"}
</span>
</p>
</body>
</html>
Listing 3.12 shows the JSON has been received and parsed correctly.
Being able to send the request body via the command line is very
useful, but most of the time we’ll want to read in a file and send that
as the body of the request. An example of this would be sending
larger amounts of JSON.
Let’s say we have the file from Listing 3.13, how would we post that
to a server?
The -d flag already gives us all that we need to get the job done. By
passing the -d flag a file name prefixed with @, it will read in that file
as the request body.
Listing 3.14
<!DOCTYPE html>
<html>
<head>
<title>Unix and Linux Commands for Developers</title>
<link href="/assets/application.css" media="all" rel="stylesheet" />
<script src="/assets/application.js"></script>
</head>
<body>
<p>
<strong>url:</strong>
<span>
http://quiet-waters-1228.herokuapp.com/echo
</span>
</p>
<p>
<strong>method:</strong>
<span>
POST
</span>
</p>
<p>
<strong>body:</strong>
<span>
{"lname"=>"Bates", "fname"=>"Mark",
"site"=>"http://www.markbates.com", "twitter"=>"http://twitter.com/markbates"}
</span>
</p>
</body>
</html>
With this simple way of using files for request bodies, it can be very
easy to write a script using cURL to upload files to a remote server.
Listing 3.15
{
"url": "http://quiet-waters-1228.herokuapp.com/echo",
"parameters": {"user":{"fname":"Mark","lname":"Bates"},"foo":"bar"},
"method": "POST",
"body": "------------------------------d6e7f7029fa5\r\nContent-Disposition:
form-data; name=\"user[fname]\"\r\n\r\nMark\r\n------------------------------
d6e7f7029fa5\r\nContent-Disposition: form-data; name=\"user[lname]\"\r\n\r\n
Bates\r\n------------------------------d6e7f7029fa5\r\nContent-Disposition:
form-data; name=\"foo\"\r\n\r\nbar\r\n------------------------------
d6e7f7029fa5--\r\n"
}
Listing 3.16
$ curl -X POST -F user[fname]=Mark -F user[lname]=Bates -F foo=bar \
-F user[photo]=@path/to/image.jpg quiet-waters-1228.herokuapp.com/echo
-H "Accept: application/json"
"Accept: application/json"
Listing 3.17
{
"body" : {
"site" : "http://www.markbates.com",
"twitter" : "http://twitter.com/markbates",
"lname" : "Bates",
"fname" : "Mark"
},
"url" : "http://quiet-waters-1228.herokuapp.com/echo",
"method" : "POST"
}
Setting the content type of a request isn’t the only header we can
specify using the -H flag. We can set any headers that the
responding server will accept. cURL allows multiple -H flags on a
request, making it easy to send several headers at once.
Listing 3.18
{
"body" : {
"site" : "http://www.markbates.com",
"twitter" : "http://twitter.com/markbates",
"lname" : "Bates",
"fname" : "Mark"
},
"url" : "http://quiet-waters-1228.herokuapp.com/echo",
"x-auth" : "1234567890",
"method" : "POST"
}
Listing 3.19
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Server: thin 1.6.1 codename Death Proof
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: da6bbeae-1b77-4f2a-bf75-300b981e108d
X-Runtime: 0.009238
X-Ua-Compatible: chrome=1
X-Xss-Protection: 1; mode=block
transfer-encoding: chunked
Connection: keep-alive
{"error":"Unknown User"}
The -u flag will let us pass a username and a password to the server
to solve this problem.
As seen in Listing 3.20 the login was successful and we now use the
information for user1.
Listing 3.20
{
"password" : "password1",
"name" : "User 1",
"id" : 1,
"username" : "user1"
}
With the -u flag we can now successfully authenticate ourselves
against any page that uses HTTP auth.
Let’s attempt to request the endpoint in question and see what the
result is.
$ curl -i quiet-waters-1228.herokuapp.com/whoami
Not surprisingly we get a 401, just like in Listing 3.19, so let’s try and
use the -u flag and see if we can gain access to the page that way.
The -D flag will tell cURL to dump headers and cookies into a
specified file in the current directory.
$ curl -X POST -D headers -u "user1:password1" \
quiet-waters-1228.herokuapp.com/login
Listing 3.21 shows the contents of the file that got created as a
result of our request.
In order to pass the headers file back to the server with our request,
we need to use the -b flag.
Listing 3.22
{
"password" : "password1",
"name" : "User 1",
"id" : 1,
"username" : "user1"
}
When using the –dump-header flag we not only capture the cookies
from a response, but also all of the headers from that response.
This may or may not be what you want.
curlhas a built-in cookie jar meant for storing just the cookies and
sending them back to the server.
To store cookies in the cookie jar we use the -c flag and give it the
name of a file we wish to store the cookies in.
Listing 3.23
{"id":1,"name":"User 1","password":"password1","username":"user1"}
$ cat cookies.txt
Listing 3.24
# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
When we look at the cookies.txt file in Listing 3.24 we see that this
time we are only storing the cookies from the response, and not the
headers as well.
Using the -b flag, as we did earlier, we can send the contents of the
cookies.txt file to the server with the request.
Listing 3.25
{
"password" : "password1",
"name" : "User 1",
"id" : 1,
"username" : "user1"
}
Listing 3.25 shows that we get a successful response from the server
when passing cookies.txt to it.
3.9 Conclusion
As you can see, cURL is an incredibly powerful tool. We have used
it to download files, upload files, access authenticated pages, and
more. This is a very small amount of the features that are available
in cURL.
The MAN page for cURL is very long, and for a very good reason.
The list of options that can be passed is dizzying. Hopefully this
chapter has given you the building blocks for using cURL on a daily
basis.
The find command is just such a search tool. With find we can
quickly search for files whose path, or name, contains a query term.
We can also find files that are owned by a particular user, are of a
certain size, have been last modified in the last n days, and much
more. In Chapter 8, we’ll use find to generate a list of files to create
an archive from.
In this chapter, we’ll look at some of the most useful features of the
find command.
The source code we’ll be using for this chapter’s examples is the
Rails source code as mentioned in the Preface.
With that knowledge in place, let’s write a simple query to find all
files that end in model.rb.
As we can see in Listing 4.1 we are only finding files that match
model.rb exactly.
Listing 4.1
./activemodel/lib/active_model/model.rb
./activerecord/lib/rails/generators/active_record/model/templates/model.rb
Listing 4.2
./activemodel/lib/active_model/model.rb
./activemodel/lib/active_model.rb
./activerecord/lib/rails/generators/active_record/model/templates/model.rb
./activerecord/test/models/arunit2_model.rb
./railties/lib/rails/generators/active_model.rb
To search within a path we can use the -path flag instead of the -
name flag. Let’s try to find any files whose path contains the word
session.
Listing 4.3
./actionpack/lib/action_dispatch/middleware/session
./actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
./actionpack/lib/action_dispatch/middleware/session/cache_store.rb
./actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
./actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
./actionpack/lib/action_dispatch/request/session.rb
./actionpack/test/dispatch/request/session_test.rb
./actionpack/test/dispatch/session
./actionpack/test/dispatch/session/abstract_store_test.rb
./actionpack/test/dispatch/session/cache_store_test.rb
./actionpack/test/dispatch/session/cookie_store_test.rb
./actionpack/test/dispatch/session/mem_cache_store_test.rb
./actionpack/test/dispatch/session/test_session_test.rb
./actionpack/test/fixtures/session_autoload_test
./actionpack/test/fixtures/session_autoload_test/session_autoload_test
./actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb
./activerecord/test/models/possession.rb
./guides/assets/images/session_fixation.png
./guides/code/getting_started/config/initializers/session_store.rb
./railties/test/application/middleware/session_test.rb
Listing 4.3 shows the results of our query. The output shows us the
many files and directories that contain the word session.
By using the -type flag, we can tell find to either look exclusively
for files, -type f, or just directories, -type d.
We can now alter our query to exclusively search for files whose
path contains session so that directories are not included in the
results.
Listing 4.4
./actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
./actionpack/lib/action_dispatch/middleware/session/cache_store.rb
./actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
./actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
./actionpack/lib/action_dispatch/request/session.rb
./actionpack/test/dispatch/request/session_test.rb
./actionpack/test/dispatch/session/abstract_store_test.rb
./actionpack/test/dispatch/session/cache_store_test.rb
./actionpack/test/dispatch/session/cookie_store_test.rb
./actionpack/test/dispatch/session/mem_cache_store_test.rb
./actionpack/test/dispatch/session/test_session_test.rb
./actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb
./activerecord/test/models/possession.rb
./guides/assets/images/session_fixation.png
./guides/code/getting_started/config/initializers/session_store.rb
./railties/test/application/middleware/session_test.rb
Listing 4.5
./actionpack/lib/action_dispatch/middleware/session
./actionpack/test/dispatch/session
./actionpack/test/fixtures/session_autoload_test
./actionpack/test/fixtures/session_autoload_test/session_autoload_test
Listing 4.6
./actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
./actionpack/test/dispatch/session/mem_cache_store_test.rb
As Listing 4.6 shows, we can combine both the -name and the -path
flags together to make our search very specific. This type of query is
an AND query. Both flags have to match for the file to be included in
the results.
We can also do OR queries in find using the -or operator and some
well placed parentheses.
Let’s write a query that will find files whose name either ends in
.gemspec or in .jpg.
$ find . \( -name \*.gemspec -or -name \*.jpg \) -type f
Listing 4.7
./actionmailer/actionmailer.gemspec
./actionmailer/test/fixtures/attachments/foo.jpg
./actionmailer/test/fixtures/attachments/test.jpg
./actionpack/actionpack.gemspec
./actionpack/test/fixtures/multipart/mona_lisa.jpg
./actionview/actionview.gemspec
./activemodel/activemodel.gemspec
./activerecord/activerecord.gemspec
./activerecord/test/assets/flowers.jpg
./activesupport/activesupport.gemspec
./guides/assets/images/akshaysurve.jpg
./guides/assets/images/oscardelben.jpg
./guides/assets/images/rails_guides_kindle_cover.jpg
./guides/assets/images/vijaydev.jpg
./rails.gemspec
./railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
./railties/railties.gemspec
Up until this point, we have been searching for files whose names or
paths match a certain pattern. Now, let’s do the opposite. We can
query for files, or directories, that don’t match a certain pattern.
Let’s say we want to find all of the files in our directory that don’t
contain the letter t somewhere in their path.
To do that we can use the -not operator in front of the -path flag.
Listing 4.8
./CONTRIBUTING.md
./Gemfile
./guides/CHANGELOG.md
./guides/rails_guides/helpers.rb
./guides/rails_guides/indexer.rb
./guides/rails_guides/kindle.rb
./guides/rails_guides/markdown/renderer.rb
./guides/rails_guides/markdown.rb
./guides/rails_guides.rb
./guides/Rakefile
./guides/source/command_line.md
./guides/source/configuring.md
./guides/source/engines.md
./guides/source/form_helpers.md
./guides/source/i18n.md
./guides/source/kindle/KINDLE.md
./guides/source/kindle/rails_guides.opf.erb
./guides/source/plugins.md
./guides/source/rails_on_rack.md
./guides/source/ruby_on_rails_guides_guidelines.md
./guides/source/upgrading_ruby_on_rails.md
./rails.gemspec
./RAILS_VERSION
./Rakefile
./README.md
./RELEASING_RAILS.rdoc
./version.rb
Another way to achieve the same result set as Listing 4.8 is to use !
instead of the -not operator. They will both give you the same
results, but I personally prefer the ! variant.
Using the -mtime flag we can search for files whose last modified
date was in the last n days.
Here we can find files who have been modified in the last day.
$ find . -mtime -1
Listing 4.9
./actionpack/lib/abstract_controller.rb
./ci/travis.rb
./Gemfile
./railties/test/engine_test.rb
The number we pass to the -mtime flag, in this case -1, is the
number of days we are interested in. This example returns files that
have been modified in the last 24 hours. An option of -2 would
represent the last 48 hours and so on.
Using the -mmin flag we can look for files that have been modified in
the last n minutes.
$ find . -mmin -5
Listing 4.10
./ci/travis.rb
4.6 Find by File Size (-size)
Another useful flag is -size, which, as its name states, allows us to
look for files whose size is over the specified amount.
Let’s do a search for files whose size is greater than 200 kilobytes.
Listing 4.11
./.git/index
./.git/objects/pack/pack-3fc5fb51b38dba971962c3dfe13c643c7c3ff357.pack
./.git/objects/pack/pack-a93c0c2849d6dba30ddb4a967548b955005ecbf1.idx
./.git/objects/pack/pack-a93c0c2849d6dba30ddb4a967548b955005ecbf1.pack
./actionview/test/template/date_helper_test.rb
./activesupport/lib/active_support/values/unicode_tables.dat
If we don’t want to see those files that are under the .git directory
we can use the ! operator we learned about in Section 4.4 to remove
them.
Listing 4.12
./actionview/test/template/date_helper_test.rb
./activesupport/lib/active_support/values/unicode_tables.dat
Table 4.1 shows the different modifiers we can add to the -size
number to specify the size of the files we want to look for.
The find tool also has the built-in ability to execute certain
commands. One of the more useful built-in commands is the -
delete flag.
The -delete flag will, as its name suggests, delete all files and
directories that match the pattern. This makes this type of
operation incredibly efficient as we can combine the finding and
deleting into one operation instead of two.
Let’s find all of the files whose name ends with .yml and delete
them from our repository. Here I’m also using the -print flag to
show the files that will be deleted.
We can verify that the -delete was performed by running the find
command and seeing that no matches are found.
4.8 Conclusion
We’ve covered a lot of what find can do in this chapter, but it is
capable of significantly more. There is not enough space here to
cover all of the different flags, options, and ways to find the files you
are looking for, but hopefully this has given you a feel for what this
indispensable tool can accomplish.
What is the grep command? grep is a tool for searching files for
search terms, similar to ack or ag that we learned about in
Chapter 2.
ack or ag both sport more modern APIs than grep. Both are faster
than grep; ag is significantly faster.
The basic usage of grep is pretty simple. Let’s search for the term
Pack in the README.md file.
Listing 5.1
are bundled together in Action Pack. You can read more about Action Pack in its
Active Record, Action Pack, and Action View can each be used independently ou...
Listing 5.11 shows that we found two lines containing Pack in the
file.
In Listing 5.22 we see that grep has found matches such as ruby and
rary (which appeared inside of “library”).
Listing 5.3
5
As we can see in Listing 5.3 the README.md file contained the pattern
ruby five times.
First let’s start by searching for the term rails in the README.md file.
Listing 5.5
gem install rails
rails new myapp
rails server
* [Getting Started with Rails](http://guides.rubyonrails.org/getting_sta...
* [Ruby on Rails Guides](http://guides.rubyonrails.org)
* [The API Documentation](http://api.rubyonrails.org)
* [Ruby on Rails Tutorial](http://ruby.railstutorial.org/ruby-on-rails-t...
[Contributing to Ruby on Rails guide](http://edgeguides.rubyonrails.org/cont...
* [](https://travi...
* [](https://ge...
Listing 5.5 shows we are only finding results in the README.md file
that match the lower case pattern, rails.
Let’s change our search to use the -i flag and compare the results.
Listing 5.6
## Welcome to Rails
Rails is a web-application framework that includes everything needed to
Understanding the MVC pattern is key to understanding Rails. MVC divides your
your application. In Rails, database-backed model classes are derived from
methods. Although most Rails models are backed by a database, models can also
providing a suitable response. Usually this means returning HTML, but Rails ...
In Rails, incoming requests are routed by Action Dispatch to an appropriate ...
or to generate the body of an email. In Rails, View generation is handled by...
Active Record, Action Pack, and Action View can each be used independently o...
In addition to them, Rails also comes with Action Mailer ([README](actionmai...
utility classes and standard library extensions that are useful for Rails, a...
independently outside Rails.
1. Install Rails at the command prompt if you haven't yet:
gem install rails
2. At the command prompt, create a new Rails application:
rails new myapp
rails server
4. Using a browser, go to http://localhost:3000 and you'll see: "Welcome abo...
* [Getting Started with Rails](http://guides.rubyonrails.org/getting_sta...
* [Ruby on Rails Guides](http://guides.rubyonrails.org)
* [The API Documentation](http://api.rubyonrails.org)
* [Ruby on Rails Tutorial](http://ruby.railstutorial.org/ruby-on-rails-t...
We encourage you to contribute to Ruby on Rails! Please check out the
[Contributing to Ruby on Rails guide](http://edgeguides.rubyonrails.org/cont...
* [](https://travi...
* [](https://ge...
Ruby on Rails is released under the [MIT License](http://www.opensource.org/...
So far we have been passing a specific file name to grep as the last
argument. To tell grep to search multiple files, we can simply pass
in multiple file names to the grep command.
Listing 5.7
README.md: gem install rails
README.md: rails new myapp
README.md: rails server
README.md: * [Getting Started with Rails](http://guides.rubyonrails.org/g...
README.md: * [Ruby on Rails Guides](http://guides.rubyonrails.org)
README.md: * [The API Documentation](http://api.rubyonrails.org)
README.md: * [Ruby on Rails Tutorial](http://ruby.railstutorial.org/ruby-...
README.md:[Contributing to Ruby on Rails guide](http://edgeguides.rubyonrail...
README.md:* [](htt...
README.md:* [](...
RELEASING_RAILS.rdoc: http://travis-ci.org/rails/rails
RELEASING_RAILS.rdoc:* [email protected]
RELEASING_RAILS.rdoc: [aaron@higgins rails (3-0-stable)]$ git checkout -b...
RELEASING_RAILS.rdoc: [aaron@higgins rails (3-0-10)]$
RELEASING_RAILS.rdoc: [aaron@higgins rails (3-0-10)]$ git log v3.0.9..
RELEASING_RAILS.rdoc:* [email protected]
RELEASING_RAILS.rdoc:* [email protected]
RELEASING_RAILS.rdoc:issues with the release candidate to the rails-core mai...
RELEASING_RAILS.rdoc:* http://weblog.rubyonrails.org
RELEASING_RAILS.rdoc:Check the rails-core mailing list and the GitHub issue ...
RELEASING_RAILS.rdoc:* [email protected]
Listing 5.76 shows results for the term rails across both files.
Notice that grep conveniently prints the name of the file next to
each line in the results, so we know which result came from which
file.
If we don’t want to list specific files, we can tell grep to search
specific files in the current directory by giving it a pattern.
Listing 5.8
install.rb: `cd #{framework} && gem build #{framework}.gemspec && gem insta...
install.rb:`gem build rails.gemspec`
install.rb:`gem install rails-#{version}.gem --no-ri --no-rdoc `
install.rb:`rm rails-#{version}.gem`
load_paths.rb:# bust gem prelude
In Listing 5.8 we told grep to search all files in the current directory
that match *.rb for the pattern gem.
$ grep -R "Read" .
Listing 5.9
./actionpack/lib/action_controller/base.rb: # Read more about writing ERB a...
./actionpack/lib/action_controller/caching/fragments.rb: # Reads a cach...
./actionpack/lib/action_controller/metal/data_streaming.rb: # Read abou...
./actionpack/lib/action_dispatch/http/request.rb: # Read the request \bod...
./actionpack/lib/action_dispatch/middleware/cookies.rb: # being written wil...
./actionpack/lib/action_dispatch/middleware/cookies.rb: "Read the...
./actionpack/lib/action_dispatch/routing/url_for.rb: # then ActionControl...
./actionpack/test/controller/log_subscriber_test.rb: assert_match(/Read f...
./actionpack/test/controller/log_subscriber_test.rb: assert_match(/Read f...
./actionpack/test/controller/log_subscriber_test.rb: assert_no_match(/Rea...
...
./guides/source/security.md:Note that _cross-site scripting (XSS) vulnerabil...
./guides/source/security.md:#### Unauthorized Reading
./railties/lib/rails/generators/actions.rb: # Reads the given file at t...
./railties/lib/rails/generators/app_base.rb: comment = 'Build JSON AP...
./railties/lib/rails/generators/app_base.rb: "Turbolinks makes fo...
./railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/a...
./railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js:...
./railties/lib/rails/generators/test_unit/model/templates/fixtures.yml:# Rea...
./railties/test/application/middleware/session_test.rb: post '/foo/read...
./railties/test/application/middleware/session_test.rb: post '/foo/read...
Listing 5.97 shows a truncated list of results for searching for the
pattern read in the current directory (specified by the . at the end)
and all subdirectories. The exact number of results I got from this
query was 138, too many to display here.
To trim our result set down even further, we can use the –include
flag to specify a pattern that each file name much match to be
included in the results.
Let’s modify our query to only search for the term Read in yml files.
Listing 5.10
./activerecord/test/fixtures/tasks.yml:# Read about fixtures at http://api.r...
./guides/code/getting_started/test/fixtures/comments.yml:# Read about fixtur...
./guides/code/getting_started/test/fixtures/posts.yml:# Read about fixtures ...
./railties/lib/rails/generators/test_unit/model/templates/fixtures.yml:# Rea...
As we can see from Listing 5.10, we have narrowed our results down
to a much more manageable four results.
$ ag Read -G yml$
Listing 5.11
activerecord/test/fixtures/tasks.yml:1:# Read about fixtures at http://api.r...
guides/code/getting_started/test/fixtures/comments.yml:1:# Read about fixtur...
guides/code/getting_started/test/fixtures/posts.yml:1:# Read about fixtures ...
railties/lib/rails/generators/test_unit/model/templates/fixtures.yml:1:# Rea...
If you compare Listing 5.108 and Listing 5.119 you’ll see that we get
the same results for both commands.
$ ps -e | grep forego
Listing 5.12
98605 ttys005 0:00.86 forego start -p 3000
Let’s search for all lines in the README.md file that don’t contain the
letter a.
Listing 5.13
Run with `--help` or `-h` for options.
## Contributing
## License
Listing 5.13 shows that our query was successful, but the results are
slightly strange in that it also returned blank lines as well.
Listing 5.14 shows the results of us using two grep queries to get all
non-blank lines that don’t contain the letter a.
5.5 Conclusion
In this chapter we looked at how to use grep to build complex
searches across multiple files.
1. This output has been truncated to better fit the format of this book. ↑
2. This output has been truncated to better fit the format of this book. ↑
3. This output has been truncated to better fit the format of this book. ↑
4. This output has been truncated to better fit the format of this book. ↑
5. This output has been truncated to better fit the format of this book. ↑
6. This output has been truncated to better fit the format of this book. ↑
7. This output has been truncated to better fit the format of this book. ↑
8. This output has been truncated to better fit the format of this book. ↑
9. This output has been truncated to better fit the format of this book. ↑
Chapter 6
Ps
Understanding what the processes running on our computers are
doing is important. Which processes are using the most memory?
Which are using the most CPU? These are important questions,
along with how to find a particular process.
$ ps
Listing 6.1
PID TTY TIME CMD
24696 ttys000 0:00.19 -bash
24697 ttys001 0:00.16 -bash
24715 ttys002 0:00.14 -bash
24721 ttys003 0:00.15 -bash
24703 ttys004 0:00.15 -bash
21686 ttys005 0:00.04 ruby /Users/markbates/scripts/ss
21690 ttys005 0:00.38 forego start -p 3000
24755 ttys005 0:00.19 -bash
24851 ttys006 0:00.69 -bash
25865 ttys007 0:00.22 -bash
25876 ttys008 0:00.10 -bash
6.1.1 Columns
Let’s quickly examine the output of Listing 6.1 and look at the
different columns of data that were printed out:
Column Definition
$ ps u
Listing 6.2
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
markbates 57896 0.0 0.0 4529729 2720 s005 S+ 10:27AM 0:00.38
forego start -p 3000
markbates 57892 0.0 0.0 2465360 7636 s005 S+ 10:27AM 0:00.04
ruby /Users/markbates/scripts/ss
markbates 25876 0.0 0.0 2489688 2400 s008 S+ Sat10AM 0:00.10 -bash
markbates 25865 0.0 0.0 2497880 2040 s007 S+ Sat10AM 0:00.22 -bash
markbates 24851 0.0 0.0 2497880 3392 s006 S+ Sat10AM 0:00.69 -bash
markbates 24755 0.0 0.0 2497880 2004 s005 S Sat10AM 0:00.21 -bash
markbates 24721 0.0 0.0 2497880 2136 s003 S+ Sat10AM 0:00.15 -bash
markbates 24715 0.0 0.0 2497880 1552 s002 S+ Sat10AM 0:00.14 -bash
markbates 24703 0.0 0.0 2497880 1424 s004 S+ Sat10AM 0:00.15 -bash
markbates 24697 0.0 0.0 2497880 1948 s001 S+ Sat10AM 0:00.16 -bash
markbates 24696 0.0 0.0 2497880 2396 s000 S+ Sat10AM 0:00.32 -bash
6.2.1 Columns
Let’s look at the additional columns that the u flag gave us.
Column Definition
$ ps -e
Listing 6.3
PID TTY TIME CMD
1 ?? 28:22.66 /sbin/launchd
17 ?? 1:19.09 /usr/libexec/UserEventAgent (System)
18 ?? 0:17.57 /usr/libexec/kextd
19 ?? 0:36.91 /usr/libexec/taskgated -s
20 ?? 0:25.96 /usr/sbin/notifyd
21 ?? 0:19.43 /usr/sbin/securityd -i
22 ?? 0:17.15 /usr/libexec/diskarbitrationd
23 ?? 0:21.38 /System/Library/CoreServices/powerd.bundle/powerd
24 ?? 5:13.79 /usr/libexec/configd
25 ?? 1:01.05 /usr/sbin/syslogd
...
24703 ttys004 0:00.15 -bash
24743 ttys005 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /bin...
24755 ttys005 0:00.21 -bash
57892 ttys005 0:00.04 ruby /Users/markbates/scripts/ss
57896 ttys005 0:00.42 forego start -p 3000
24810 ttys006 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /bin...
24851 ttys006 0:00.70 -bash
25864 ttys007 0:00.01 login -pfl markbates /bin/bash -c exec -la bash /bin...
25865 ttys007 0:00.24 -bash
25866 ttys008 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /bin...
25876 ttys008 0:00.10 -bash
Although Listing 6.33 has been truncated, you can see that we now
have a mix of “system” processes as well as “user” processes.
$ ps ax
Listing 6.4
PID TT STAT TIME COMMAND
1 ?? Ss 28:34.79 /sbin/launchd
17 ?? Ss 1:19.61 /usr/libexec/UserEventAgent (System)
18 ?? Ss 0:17.63 /usr/libexec/kextd
19 ?? Ss 0:37.35 /usr/libexec/taskgated -s
20 ?? Ss 0:26.22 /usr/sbin/notifyd
21 ?? Ss 0:19.52 /usr/sbin/securityd -i
22 ?? Ss 0:17.24 /usr/libexec/diskarbitrationd
23 ?? Ss 0:21.71 /System/Library/CoreServices/powerd.bundle/powerd
24 ?? Us 5:15.98 /usr/libexec/configd
25 ?? Ss 1:01.66 /usr/sbin/syslogd
...
24703 s004 S+ 0:00.15 -bash
24743 s005 Ss 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /b...
24755 s005 S 0:00.21 -bash
57892 s005 S+ 0:00.04 ruby /Users/markbates/scripts/ss
57896 s005 S+ 0:00.43 forego start -p 3000
24810 s006 Ss 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /b...
24851 s006 S+ 0:00.71 -bash
25864 s007 Ss 0:00.01 login -pfl markbates /bin/bash -c exec -la bash /b...
25865 s007 S+ 0:00.31 -bash
25866 s008 Ss 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /b...
25876 s008 S+ 0:00.10 -bash
$ ps -U root
Listing 6.5
PID TTY TIME CMD
1 ?? 28:36.67 /sbin/launchd
17 ?? 1:19.66 /usr/libexec/UserEventAgent (System)
18 ?? 0:17.63 /usr/libexec/kextd
19 ?? 0:37.49 /usr/libexec/taskgated -s
20 ?? 0:26.29 /usr/sbin/notifyd
21 ?? 0:19.52 /usr/sbin/securityd -i
22 ?? 0:17.24 /usr/libexec/diskarbitrationd
23 ?? 0:21.76 /System/Library/CoreServices/powerd.bundle/powerd
24 ?? 5:16.27 /usr/libexec/configd
25 ?? 1:01.75 /usr/sbin/syslogd
...
866 ?? 0:00.06 /System/Library/Frameworks/CoreServices.framework/...
1000 ?? 0:18.78 /usr/libexec/systemstatsd
2065 ?? 0:00.53 /System/Library/Filesystems/AppleShare/check_afp.app/...
4804 ?? 0:00.01 /usr/libexec/periodic-wrapper daily
15536 ?? 0:00.00 /usr/sbin/aslmanager -s /var/log/eventmonitor
15537 ?? 0:00.00 /usr/sbin/aslmanager -s /var/log/performance
26161 ?? 0:00.76 /System/Library/Frameworks/CoreMediaIO.framework/...
26865 ?? 0:00.01 com.apple.cmio.registerassistantservice
33266 ?? 0:01.57 /usr/libexec/syspolicyd
64100 ?? 0:00.12 /usr/sbin/ocspd
66252 ?? 0:00.00 /usr/libexec/periodic-wrapper weekly
Compare Listing 6.55 and Listing 6.66 and you can see the different
processes associated with each user.
$ ps -U markbates
Listing 6.6
PID TTY TIME CMD
351 ?? 0:23.19 /sbin/launchd
355 ?? 0:10.19 /usr/libexec/UserEventAgent (Aqua)
356 ?? 1:45.54 /usr/sbin/distnoted agent
359 ?? 0:17.99 /usr/sbin/cfprefsd agent
366 ?? 0:55.47 /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock
367 ?? 6:17.86 /System/Library/CoreServices/SystemUIServer.app/...
368 ?? 2:29.01 /System/Library/CoreServices/Finder.app/Contents/...
371 ?? 0:05.79 /usr/libexec/xpcd
372 ?? 0:04.46 /usr/libexec/sharingd
373 ?? 0:00.01 /usr/sbin/pboard
374 ?? 0:01.76 /System/Library/PrivateFrameworks/TCC.framework/...
...
24698 ttys004 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /bin/bash
24703 ttys004 0:00.15 -bash
24743 ttys005 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /bin/bash
24755 ttys005 0:00.21 -bash
57892 ttys005 0:00.04 ruby /Users/markbates/scripts/ss
57896 ttys005 0:00.43 forego start -p 3000
24810 ttys006 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /bin/bash
24851 ttys006 0:00.72 -bash
25864 ttys007 0:00.01 login -pfl markbates /bin/bash -c exec -la bash /bin/bash
25865 ttys007 0:00.31 -bash
25866 ttys008 0:00.02 login -pfl markbates /bin/bash -c exec -la bash /bin/bash
25876 ttys008 0:00.10 -bash
$ ps -L
comm command
pid process ID
$ ps -O etime,%cpu,%mem
Listing 6.7
PID ELAPSED %CPU %MEM TT STAT TIME COMMAND
24696 03-06:31:19 0.0 0.0 s000 S+ 0:00.34 -bash
24697 03-06:31:19 0.0 0.0 s001 S+ 0:00.16 -bash
24715 03-06:31:19 0.0 0.0 s002 S+ 0:00.14 -bash
24721 03-06:31:19 0.0 0.0 s003 S+ 0:00.22 -bash
24703 03-06:31:19 0.0 0.0 s004 S+ 0:00.15 -bash
24755 03-06:31:19 0.0 0.0 s005 S 0:00.21 -bash
57892 06:11:07 0.0 0.0 s005 S+ 0:00.04 ruby /Users/markbates/scripts/ss
57896 06:11:07 0.0 0.0 s005 S+ 0:00.46 forego start -p 3000
24851 03-06:31:19 0.0 0.0 s006 S+ 0:00.72 -bash
25865 03-06:31:19 0.0 0.0 s007 S+ 0:00.31 -bash
25876 03-06:31:19 0.0 0.0 s008 S+ 0:00.14 -bash
It’s important to note that when we look at things like current CPU
and memory usage with ps, they are static snapshots of those
numbers at that moment in time. They are not “live” numbers that
will continue to update in real-time. Should you need real-time
data, you might consider using the top command instead.
6.6 Sorting
The ps command gives us a few different ways to sort the results we
get. Two of the more useful ones are the -m flag, which sorts by
memory usage, and the -r flag, that sorts by CPU usage.
While looking at both of these examples, we’ll use the -u flag that
we learned about in Section 6.4 to scope results to the root user.
We’ll also use the -O flag we saw in Section 6.5 to display either
memory or CPU usage.
$ ps -m -O %mem -u root
Listing 6.8
PID %MEM TT STAT TIME COMMAND
154 1.5 ?? Ss 66:49.98 /System/Library/Frameworks/ApplicationServices...
174 1.0 ?? Ss 29:44.90 /System/Library/Frameworks/CoreServices.framew...
100 0.4 ?? Ss 49:42.27 /System/Library/Frameworks/CoreServices.framew...
70322 0.3 ?? Ss 0:04.58 /System/Library/PrivateFrameworks/PackageKit.f...
128 0.3 ?? Ss 650:05.90 /Applications/Leap Motion.app/Contents/MacOS/l...
5835 0.2 ?? Ss 0:01.46 /usr/sbin/ocspd
115 0.2 ?? Ss 1:46.32 /System/Library/CoreServices/launchservicesd
103 0.1 ?? Ss 0:16.27 /System/Library/CoreServices/loginwindow.app/C...
337 0.1 ?? S 29:54.94 /Library/Parallels/Parallels Service.app/Conte...
51 0.1 ?? Ss 11:47.34 /System/Library/Frameworks/CoreServices.framew...
17 0.1 ?? Ss 1:41.91 /usr/libexec/UserEventAgent (System)
28 0.1 ?? Ss 2:14.83 /usr/libexec/opendirectoryd
86 0.1 ?? SNs 0:38.33 /usr/libexec/warmd
32 0.1 ?? Ss 1:17.58 /System/Library/CoreServices/coreservicesd
26161 0.1 ?? Ss 0:00.96 /System/Library/Frameworks/CoreMediaIO.framewo...
349 0.1 ?? Ss 0:01.04 /System/Library/PrivateFrameworks/SoftwareUpda...
19 0.0 ?? Ss 0:48.08 /usr/libexec/taskgated -s
...
Listing 6.88 shows the top processes for the root user, sorted by
their memory usage.
$ ps -r -O %cpu -u root
Listing 6.9
PID %CPU TT STAT TIME COMMAND
130 50.6 ?? SNs 2303:23.91 /usr/bin/java -Dapp=CrashPlanService -Xmn10m...
128 41.2 ?? Rs 656:28.86 /Applications/Leap Motion.app/Contents/MacOS/...
154 3.0 ?? Us 68:09.18 /System/Library/Frameworks/ApplicationService...
115 2.3 ?? Ss 2:16.12 /System/Library/CoreServices/launchservicesd
337 1.7 ?? S 30:55.44 /Library/Parallels/Parallels Service.app/Cont...
32 1.1 ?? Ss 1:39.38 /System/Library/CoreServices/coreservicesd
23 0.4 ?? Ss 0:30.84 /System/Library/CoreServices/powerd.bundle/po...
100 0.3 ?? Ss 51:01.97 /System/Library/Frameworks/CoreServices.frame...
25 0.3 ?? Ss 1:24.04 /usr/sbin/syslogd
19 0.2 ?? Ss 0:51.95 /usr/libexec/taskgated -s
51 0.1 ?? Ss 12:20.59 /System/Library/Frameworks/CoreServices.frame...
174 0.1 ?? Ss 30:38.53 /System/Library/Frameworks/CoreServices.frame...
864 0.0 ?? Ss 0:00.06 /sbin/launchd
...
Listing 6.99 shows the top processes for the root user, sorted by
their CPU usage.
6.7 Conclusion
The ps command is one of those commands that you’ll use almost
daily. With the numerous ways you can sort, filter, and present
processes, it is easy to find the process information you are looking
for.
1. http://en.wikipedia.org/wiki/Tty ↑
2. The listing has been wrapped to fit in the box. ↑
3. This output has been truncated to better fit the format of this book. ↑
4. This output has been truncated to better fit the format of this book. ↑
5. This output has been truncated to better fit the format of this book. ↑
6. This output has been truncated to better fit the format of this book. ↑
http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?
topic=/com.ibm.aix.cmds/doc/aixcmds4/ps.htm
↑
8. This output has been truncated to better fit the format of this book. ↑
9. This output has been truncated to better fit the format of this book. ↑
Chapter 7
Sed
sed is a stream editor that lets you quickly edit files or streams
using pattern matching and replacements.
For this chapter we’ll be using the file in Listing 7.1 as the basis for
all of our examples.
$ cat birthday.txt
Listing 7.1
Happy Birthday to You, cha, cha, cha.
Happy Birthday to You, cha, cha, cha.
Happy Birthday Dear (name)
Happy Birthday to You, cha, cha, cha.
If you are on a Mac, the best and easiest way to install gnu-sed is
using Homebrew.
Let’s use sed to replace all vowels from our example file and replace
them with *.
In Listing 7.2 we can see that only the first vowel on each line was
replaced with a *. Before we talk about why that is and how to fix it,
let’s examine what we told sed to do.
In Listing 7.2 we saw that only the first vowel in each line was
replaced. We can update our regular expression to use the g option,
which means “global”, to replace all vowels on each line with *.
Listing 7.3
H*ppy B*rthd*y t* Y**, ch*, ch*, ch*.
H*ppy B*rthd*y t* Y**, ch*, ch*, ch*.
H*ppy B*rthd*y D**r (n*m*)
H*ppy B*rthd*y t* Y**, ch*, ch*, ch*.
Let’s write a sed script that will replace the second occurrence of the
word cha on each line with the word foo.
Listing 7.4
Happy Birthday to You, cha, foo, cha.
Happy Birthday to You, cha, foo, cha.
Happy Birthday Dear (name)
Happy Birthday to You, cha, foo, cha.
In Listing 7.4 we replaced the g option with the number 2 to tell sed
to replace the second occurrence of the pattern on each line that it is
found.
On most Unix and Linux systems you can use the -i flag to allow
sed to edit the file in place. This means your edits will be saved
directly to the file.
Let’s use -i to replace the (name) placeholder in the file with the
name Mark.
When using the -i flag there will be no output if the command was
successful. We can print the contents of the file to the screen to
verify our edits using the cat command (that we’ll learn about in
Section 9.2), as seen in Listing 7.5.
Let’s replace all instances of the word happy, regardless of its case,
to the word Merry.
Listing 7.7
Merry Birthday to You, cha, cha, cha.
Merry Birthday to You, cha, cha, cha.
Merry Birthday Dear (name)
Merry Birthday to You, cha, cha, cha.
Listing 7.8
*************************************
*************************************
Happy Birthday Dear (name)
*************************************
As you can see in Listing 7.8 we proceeded our search pattern with
/cha/. This tells sed to match the line against this pattern, and if
the line matches, then it performs the subsequent search and
replace.
The & variable can be used in the replace section of your sed script
to represent a match from the search part of the script.
sed has several special characters we can use in the replace section
of our script to manipulate the data we get using the & variable.
The first such character we use is \u. The \u character will convert
whatever comes after it to uppercase.
Let’s write a script that combines \u and & to capitalize all of the
vowels in the example file.
Listing 7.9
HAppy BIrthdAy tO YOU, chA, chA, chA.
HAppy BIrthdAy tO YOU, chA, chA, chA.
HAppy BIrthdAy DEAr (nAmE)
HAppy BIrthdAy tO YOU, chA, chA, chA.
We can use the same technique, this time using the \l character, to
lower the case of all of the capital letters in the example file.
Listing 7.10
happy birthday to you, cha, cha, cha.
happy birthday to you, cha, cha, cha.
happy birthday dear (name)
happy birthday to you, cha, cha, cha.
Using the -n flag we can suppress the default output of sed. For
example, the following command won’t print anything to the
console window.
By using the p option we can tell sed to print only the changes to the
console for us.
Listing 7.11
Happy Birthday Dear Mark
In Listing 7.11 we see just the one line of the file that the search and
replace query affected.
The -n flag takes an optional argument that we can use to print out
specific lines of content.
Using the -n flag and p option, we can write a query that will print
every other line of our example file to the console.
Listing 7.13
Happy Birthday to You, cha, cha, cha.
Happy Birthday Dear (name)
Using the d option, we can tell sed to delete any lines that match a
specific pattern.
Listing 7.14
Happy Birthday to You, cha, cha, cha.
Happy Birthday to You, cha, cha, cha.
Happy Birthday to You, cha, cha, cha.
In Listing 7.14 we told sed to delete any lines that match the pattern
(name). It should be pointed out that this is only changing the
output, and has left the original file untouched. If you want to write
these modifications back to the file, you can use the techniques we
learned about in Section 7.3.1.
Listing 7.15 shows the contents of the file we’re going to use for the
examples in this section.
Listing 7.15: $ cat example.html
<p>
This <i>is</i> some <b>HTML</b>.
</p>
<a href="http://www.conqueringthecommandline.com">Conquering the Command Line</a>
Lets use sed to strip all of the HTML tags out of the file.
Listing 7.16
Listing 7.16 doesn’t use anything new about sed that we don’t
already know, just a different search and replace pattern.
The problem with Listing 7.16 is that while it stripped out all of the
HTML tags from the file, it left us with blank lines, as we can see in
Listing 7.17
Listing 7.17
There are a couple of different ways we can fix this problem. The
first way would be use the pipe operator, |, to take the output of
Listing 7.16 and send it to a second sed command to delete the blank
lines using the d option we learned about in Section 7.8. We can see
the results of this approach in Listing 7.18
$ sed 's/<[^>]*>//g' example.html | sed '/^$/d'
Listing 7.18
This is some HTML.
Conquering the Command Line
Listing 7.19
This is some HTML.
Conquering the Command Line
7.10 Conclusion
As we’ve seen in this chapter, sed is a very simple editor that allows
us to quickly edit files or streams. A basic understanding of sed can
come in very handy when you’re working on a bare machine that
has yet to have a more sophisticated editor installed.
sed can easily be scripted. This makes it a great tool to use in
deployment scripts to update configuration files or other similar
operations.
1. Feel free and use this script on all of those top secret government projects you are
working on. ↑
Chapter 8
Tar
There will come a time when you want to take several files and
archive them together into a single file - this is where the tar (tape
archive) command comes in.
tar can quickly join together multiple files into one larger file, while
still preserving meta-data such as Unix permissions. By default tar
does not compress files, but it does have a flag that will compress
the archive using gzip. We’ll learn about this later in Section 8.7.
The source code we’ll be using for this chapter’s examples is the
Rails source code, as mentioned in the Preface.
$ tar -c tools/
The results of our command can be seen in Listing 8.1.
Listing 8.1
tools/000755 000765 000024 00000000000 12244661361 013337
5ustar00markbatesstaff000000 000000 tools/console000755 000765 000024 00000000255
12244661361 014731 0ustar00markbatesstaff000000 000000 #!/usr/bin/env ruby
require File.expand_path('../../load_paths', __FILE__)
require 'rails/all'
require 'active_support/all'
require 'irb'
require 'irb/completion'
IRB.start
tools/profile000755 000765 000024 00000003451 12244661361 014730
0ustar00markbatesstaff000000 000000 #!/usr/bin/env ruby
# Example:
# tools/profile activesupport/lib/active_support.rb
ENV['NO_RELOAD'] ||= '1'
ENV['RAILS_ENV'] ||= 'development'
require 'benchmark'
module RequireProfiler
private
def require(file, *args) RequireProfiler.profile(file) { super } end
def load(file, *args) RequireProfiler.profile(file) { super } end
@depth, @stats = 0, []
class << self
attr_accessor :depth
attr_accessor :stats
def profile(file)
stats << [file, depth]
self.depth += 1
result = nil
elapsed = Benchmark.realtime { result = yield }
self.depth -= 1
stats.pop if stats.last.first == file
stats << [file, depth, elapsed] if result
result
end
end
end
GC.start
before_rss = `ps -o rss= -p #{Process.pid}`.to_i
path = ARGV.shift
if mode = ARGV.shift
require 'ruby-prof'
RubyProf.measure_mode = RubyProf.const_get(mode.upcase)
RubyProf.start
else
Object.instance_eval { include RequireProfiler }
end
if mode
if printer = ARGV.shift
RubyProf.const_get("#{printer.to_s.classify}Printer").new(results)
elsif RubyProf.const_defined?(:CallStackPrinter)
File.open("#{File.basename(path, '.rb')}.#{mode}.html", 'w') do |out|
RubyProf::CallStackPrinter.new(results).print(out)
end
else
File.open("#{File.basename(path, '.rb')}.#{mode}.callgrind", 'w') do |out|
RubyProf::CallTreePrinter.new(results).print(out)
end
end
end
The second thing that should be noted is that the archive was
printed to “standard out” (STDOUT)1 and not saved to a file. We will
learn how to save the archive to a file in Section 8.2.
If the creation of the archive file was successful, the tar command
will produce no output.
Using the -v flag we can see which files are being added to our
archive. This will output the list of files in the archive after it has
been generated.
Listing 8.3
a tools
a tools/console
a tools/profile
Listing 8.3 shows the output of the tar command using the -v flag.
We will be using this flag for the rest of the examples in this
chapter.
Listing 8.4
a tools
a tools/console
a tools/profile
a tasks
a tasks/release.rb
a install.rb
a rails.gemspec
a version.rb
First let’s build a find query that finds all of the files ending in
.gemspec.
Listing 8.5
./actionmailer/actionmailer.gemspec
./actionpack/actionpack.gemspec
./actionview/actionview.gemspec
./activemodel/activemodel.gemspec
./activerecord/activerecord.gemspec
./activesupport/activesupport.gemspec
./rails.gemspec
./railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
./railties/railties.gemspec
Listing 8.5 shows that our find query is working correctly. Now we
can use | to pipe the output of the find query to the tar command.
The -T flag will read in a list of file names from another file. In our
case we are going to use - in place of the name of a file. This tells
tar that it should read in the list of files from the find query we
piped in.
Listing 8.6
a ./actionmailer/actionmailer.gemspec
a ./actionpack/actionpack.gemspec
a ./actionview/actionview.gemspec
a ./activemodel/activemodel.gemspec
a ./activerecord/activerecord.gemspec
a ./activesupport/activesupport.gemspec
a ./rails.gemspec
a ./railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
a ./railties/railties.gemspec
In Listing 8.6 we can see that the files from our original find query
have been added to the archive.
Listing 8.7
tools/
tools/console
tools/profile
tasks/
tasks/release.rb
install.rb
rails.gemspec
version.rb
Listing 8.8
a Gemfile
a README.md
Listing 8.9: $ tar -tf foo.tar
tools/
tools/console
tools/profile
tasks/
tasks/release.rb
install.rb
rails.gemspec
version.rb
Gemfile
README.md
We can see in Listing 8.8 and Listing 8.9 that by using the -r flag,
the files we have specified have been added to the archive.
As was the case in Section 8.4 where we needed to add missing files
to the archive, sometimes it is necessary to update files that are
already in the archive. To do this we can use the -u flag.
Listing 8.10
a version.rb
Listing 8.11
x tools/
x tools/console
x tools/profile
x tasks/
x tasks/release.rb
x install.rb
x rails.gemspec
x version.rb
x Gemfile
x README.md
Listing 8.11 shows the files that have been extracted from the
archive. These files will also be restored with their original meta-
data, permissions, owner, etc…
Up until this point we have been extracting all of the files to the
current directory we are in, but we can easily extract to a different
location.
First, let’s create a new folder, named myfolder, that we will extract
all of the files to.
$ mkdir myfolder
Using the -C flag we can pass a folder to the tar command as the
location we want to extract the file to.
Listing 8.13
x tools/
x tools/console
x tools/profile
x tasks/
x tasks/release.rb
x install.rb
x rails.gemspec
x version.rb
x Gemfile
x README.md
Listing 8.13 shows that all of the files have been extracted. We can
use the find tool we learned about in Chapter 4 to look at the
structure of the myfolder directory.
$ find ./myfolder
Listing 8.14
./myfolder
./myfolder/Gemfile
./myfolder/install.rb
./myfolder/rails.gemspec
./myfolder/README.md
./myfolder/tasks
./myfolder/tasks/release.rb
./myfolder/tools
./myfolder/tools/console
./myfolder/tools/profile
./myfolder/version.rb
As we can see in Listing 8.14 all of the files were extracted to their
appropriate locations based on how they were archived.
Listing 8.17
x activerecord/
x activerecord/activerecord.gemspec
x activerecord/CHANGELOG.md
x activerecord/examples/
...
x activerecord/lib/active_record/associations/builder/singular_association.rb
x activerecord/examples/.gitignore
x activerecord/examples/performance.rb
x activerecord/examples/simple.rb
Listing 8.17 shows a truncated list of the files that were extracted.
8.9 Conclusion
In this chapter we learned how to use tar to:
1. Standard out is where Unix/Linux will write output by default. Typically this is the
console window. ↑
2. I’m not going to show you the verbose output of this command, as it is rather lengthy
and doesn’t really tell us anything important. Feel free and add the -v flag on your
own to see the output. ↑
3. I’m not going to show you the verbose output of this command, as it is rather lengthy
and doesn’t really tell us anything important. Feel free and add the -v flag on your
own to see the output. ↑
Chapter 9
Extras
This chapter contains a few little extra commands that I think are
both fun and useful. Some are not available on all systems, but
hopefully they’ll be available on yours.
9.1 Cal
If you spend your life living in a terminal window, the cal command
can be quite useful for helping you check dates.
The basic usage of cal will print out the current month’s calendar,
as seen in Listing 9.1.
$ cal
Listing 9.1
December 2013
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
If you need to see the current year’s calendar at a glance, the -y flag
will print the full year’s calendar.
$ cal -y
Listing 9.2
2013
If you pass cal a single integer parameter it will print out a calendar
for that year.
$ cal 2015
Listing 9.3
2015
$ cal 8 2016
Listing 9.4
August 2016
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
9.2 Cat
The cat command is short for concatenate, and it does just that. It
will allow us to concatenate multiple files together, but it also has a
few extra tricks up its sleeve.
Without any extra flags, cat will print out the contents of a file to
the standard output, usually your terminal window.
$ cat file1.txt
Listing 9.5
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ut felis sit amet
mi malesuada convallis. In eget rutrum lacus. Donec consequat, orci sit amet
porttitor hendrerit, risus mauris placerat erat, eget vestibulum diam dolor eu
erat. Donec a neque sit amet eros porta volutpat. Vestibulum lectus magna,
ultrices at rutrum euismod, scelerisque ac urna. Suspendisse augue ipsum,
condimentum at fringilla ut, dapibus eu nisi. Nam pellentesque ante convallis,
sagittis nunc a, vehicula turpis. Sed quis velit pulvinar, convallis magna in,
viverra sapien.
Listing 9.6
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ut felis sit amet
mi malesuada convallis. In eget rutrum lacus. Donec consequat, orci sit amet
porttitor hendrerit, risus mauris placerat erat, eget vestibulum diam dolor eu
erat. Donec a neque sit amet eros porta volutpat. Vestibulum lectus magna,
ultrices at rutrum euismod, scelerisque ac urna. Suspendisse augue ipsum,
condimentum at fringilla ut, dapibus eu nisi. Nam pellentesque ante convallis,
sagittis nunc a, vehicula turpis. Sed quis velit pulvinar, convallis magna in,
viverra sapien.
Integer suscipit augue a tempor pellentesque. Proin tincidunt magna in luctus
vulputate. Duis euismod elit sit amet pellentesque hendrerit. Suspendisse blandit
euismod mauris eu congue. Ut condimentum et est sed lobortis. Etiam vel neque
faucibus turpis accumsan imperdiet. Nullam nisl felis, pharetra quis orci vitae,
sagittis gravida augue. Interdum et malesuada fames ac ante ipsum primis in
faucibus. Maecenas vulputate tempus adipiscing. Cras aliquet nibh a ligula
varius, a varius massa tempus. Etiam porttitor neque sit amet ante laoreet, vitae
euismod ipsum ullamcorper. Nullam placerat sed est in tincidunt.
Listing 9.6 shows the two files joined together into one file and
printed to the standard output (terminal window).
9.2.3 Save Multiple Files to a New File
We can then use the cat command to view the contents of the new
file.
$ cat new_file.txt
$ cat -b big_file.txt
Listing 9.8
1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ut
felis sit amet mi malesuada convallis. In eget rutrum lacus. Donec consequat,
orci sit amet porttitor hendrerit, risus mauris placerat erat, eget vestibulum
diam dolor eu erat. Donec a neque sit amet eros porta volutpat. Vestibulum
lectus magna, ultrices at rutrum euismod, scelerisque ac urna. Suspendisse
augue ipsum, condimentum at fringilla ut, dapibus eu nisi. Nam pellentesque
ante convallis, sagittis nunc a, vehicula turpis. Sed quis velit pulvinar,
convallis magna in, viverra sapien.
2 Integer suscipit augue a tempor pellentesque. Proin tincidunt magna
in luctus vulputate. Duis euismod elit sit amet pellentesque hendrerit.
Suspendisse blandit euismod mauris eu congue. Ut condimentum et est sed
lobortis. Etiam vel neque faucibus turpis accumsan imperdiet. Nullam nisl
felis, pharetra quis orci vitae, sagittis gravida augue. Interdum et
malesuada fames ac ante ipsum primis in faucibus. Maecenas vulputate tempus
adipiscing. Cras aliquet nibh a ligula varius, a varius massa tempus. Etiam
porttitor neque sit amet ante laoreet, vitae euismod ipsum ullamcorper.
Nullam placerat sed est in tincidunt.
3 Nunc vel massa vel nibh auctor aliquam. Fusce non interdum purus.
Proin at vestibulum nisl. Mauris venenatis rutrum cursus. Nunc quis rutrum
nulla. Praesent ac faucibus ligula. Donec non velit quis risus aliquet
sollicitudin. Fusce sed vestibulum est.
4 Sed feugiat lorem eu porta sodales. Ut egestas urna orci, eget
fringilla lectus malesuada ac. Etiam malesuada nulla et luctus ullamcorper.
Fusce et enim nulla. Vivamus pharetra eros non convallis fermentum. Nulla
viverra nunc nec faucibus tempor. Duis nibh ligula, tincidunt non
ullamcorper eget, iaculis vel mi. Duis tristique imperdiet venenatis.
Praesent dictum sit amet elit sit amet aliquam. Proin convallis eros sed
tortor sodales elementum. Lorem ipsum dolor sit amet, consectetur
adipiscing elit.
5 Sed eu dignissim augue. In accumsan enim diam, eu convallis nisl
pellentesque a. Pellentesque sed lorem dui. Praesent mattis ut nulla at
condimentum. Nam ut nisi porttitor, feugiat libero interdum, sollicitudin eros.
Maecenas at metus vehicula, ornare diam vitae, iaculis arcu. Duis eu mi eu
ipsum blandit viverra in nec quam. Nulla auctor, velit vel ornare congue,
libero mi porttitor mauris, nec porta orci lorem lacinia eros. Sed tristique
aliquet congue. Interdum et malesuada fames ac ante ipsum primis in faucibus.
9.3 Kill
The kill command is, unfortunately, poorly named. Its name
would imply that its sole purpose is that of mischief, when in reality
its purpose is to simply send messages to processes. A few of these
signals will forcefully terminate a process. Others will simply tell
the process to shutdown when it is ready.
Table 9.2 shows a list of the different signals (and their meaning)
that can be sent to a process from the kill command.
Listing 9.9
$ kill 123456
Listing 9.10
$ kill -9 123456
Listing 9.11
$ kill -s SIGKILL 123456
In Listing 9.11 we use the -s flag and give it the name of the signal
we want to send, SIGKILL.
Both Listing 9.10 and Listing 9.11 send the same information, and
have the result, on the specified process.
9.4 Man
The goal of this book is to help you master the Unix and Linux
commands that will provide you with the most value on a daily
basis.
We’ve covered a key subset of flags and options that will be most
useful in your day-to-day work as a software developer. In some
circumstances you’ll need to go beyond the scope of this book for
more information.
$ man mkdir
Listing 9.12
MKDIR(1) BSD General Commands Manual MKDIR(1)
NAME
mkdir -- make directories
SYNOPSIS
mkdir [-pv] [-m mode] directory_name ...
DESCRIPTION
The mkdir utility creates the directories named as operands, in the order
specified, using mode rwxrwxrwx (0777) as modified by the current umask(2).
-m mode
Set the file permission bits of the final created directory to the
specified mode. The mode argument can be in any of the formats
specified to the chmod(1) command. If a symbolic mode is specified,
the operation characters ``+'' and ``-'' are interpreted relative to an
initial mode of ``a=rwx''.
DIAGNOSTICS
The mkdir utility exits 0 on success, and >0 if an error occurs.
SEE ALSO
rmdir(1)
COMPATIBILITY
The -v option is non-standard and its use in scripts is not recommended.
STANDARDS
The mkdir utility is expected to be IEEE Std 1003.2 (``POSIX.2'')
compatible.
HISTORY
A mkdir command appeared in Version 1 AT&T UNIX.
The man command does a lot more than just display manual
information. For example, it helps you to generate man pages, but
that’s unlikely something you’re going to use that often.
For more information on man you can use the very “meta” command
found in Listing 9.13.
Listing 9.13
$ man man
So what does pbcopy do? It will read input from the standard output
and copy that data into the system’s paste buffer, to be used in other
places.
We can use the cat command from Section 9.2 to read in a file and
then use the pipe operator, |, to send the result to pbcopy.
Listing 9.14 shows the data in the paste buffer ready to be pasted
into what application you need it for.
The pbpaste command lets you take data from the system’s paste
buffer and write it to standard out.
Let’s copy a file into the paste buffer using the pbcopy command.
We’ll use the example file from the sed chapter, Chapter 7.
$ pbpaste | ag name
Listing 9.15
Happy Birthday Dear (name)
In Listing 9.15 we took the data from the system’s paste buffer and
piped it into the ag command (Chapter 2) to search for the word
“name”.
9.7 Tail
The tail command allows us to look at the end of a file, and even
more so will let us watch a file as it is being written to, making it
perfect for monitoring log files in a production environment.
By default, when you pass a file name to the tail command the last
ten lines of the file will be printed to the screen, and tail will exit.
Listing 9.16 shows the last ten lines of the /var/log/system.log file.
$ tail /var/log/system.log
Listing 9.16
Dec 5 15:46:22 markmini.home Google Chrome Helper[62354]: Process unable to ...
Dec 5 15:46:22 markmini.home Google Chrome Helper[62354]: Process unable to ...
Dec 5 15:46:22 markmini.home Google Chrome Helper[62354]: CGSLookupServerRoo...
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: Internals of CFAll...
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: Process unable to ...
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: Process unable to ...
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: CGSLookupServerRoo...
Dec 5 15:49:19 markmini.home mds[100]: (Warning) Volume: vsd:0x7fcd9c5a0800 ...
DisabledRecycleCount = 8;
}
$ tail -n 5 /var/log/system.log
Listing 9.17
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: Process unable to ...
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: CGSLookupServerRoo...
Dec 5 15:49:19 markmini.home mds[100]: (Warning) Volume: vsd:0x7fcd9c5a0800 ...
DisabledRecycleCount = 8;
}
Using the -r flag we can reverse the direction of how tail displays
the selected lines of the file to us. By default, the last line of the
output is the last line of the file, but the -r flag will reverse that to
make the last line of the file the first line of the output.
$ tail -r -n 5 /var/log/system.log
Listing 9.18
}
DisabledRecycleCount = 8;
Dec 5 15:49:19 markmini.home mds[100]: (Warning) Volume: vsd:0x7fcd9c5a0800 ...
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: CGSLookupServerRoo...
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]: Process unable to ...
Listing 9.18 shows the last five lines of a file with the newest line at
the top of the output, and the oldest line at the bottom of the
output.
Quite possibly one of the most used commands and flags in any
production environment is the tail command with the -f flag.
When using the -f flag, tail will never exit and will continue to
output new data as it is added to the end of the watched file.
$ tail -f /var/log/system.log
We can easily use the pipe operator, |, to send the live stream of
data from tail to a command (such as ag that we learned about in
Chapter 2) to filter the data easily for us.
Listing 9.19
Dec 5 15:46:22 markmini.home Google Chrome Helper[62354]:
CGSLookupServerRootPort: Failed to look up the port for
"com.apple.windowserver.active" (1100)
Dec 5 15:46:24 markmini.home Google Chrome Helper[62357]:
CGSLookupServerRootPort: Failed to look up the port for
"com.apple.windowserver.active" (1100)
9.8 Tree
Using the tree command, you can recursively list the contents of a
directory in a tree-like format. This is handy when you want to get a
high-level view of all the directories and files inside of a project for
example.
By default, tree will list all of the directories and files in a given
directory, but it also comes with many flags that will alter the level
of detail you get back.
9.8.1 Installation
tree may or may not be installed by default on your machine. If
tree is not installed then you should visit the tree homepage for
instructions on how to install it on your system.
If you are on a Mac, the best and easiest way to install tree is using
Homebrew.
By default when you use the tree command, it will output a list of
all of the files and directories in the current directory, recursively.
$ tree
Listing 9.20
.
├── assets
│ ├── images
│ │ └── image.jpg
│ ├── javascripts
│ │ ├── application.js
│ │ └── curly.js.coffee
│ └── stylesheets
│ ├── application.css
│ └── curly.css.scss
├── controllers
│ ├── application_controller.rb
│ ├── concerns
│ └── curly_controller.rb
├── helpers
│ ├── application_helper.rb
│ └── curly_helper.rb
├── mailers
├── models
│ └── concerns
└── views
├── curly
│ └── echo.html.erb
└── layouts
└── application.html.erb
In Listing 9.20 we can see a recursive list of all files and directories
in the current directory.
The tree command will let us limit the depth of its recursion if we
want using the -L flag and giving it a number of levels we want the
recursion to go. This can be helpful in very deep directories, where
you only want an overview of what’s under the surface.
$ tree -L 2
Listing 9.21
.
├── assets
│ ├── images
│ ├── javascripts
│ └── stylesheets
├── controllers
│ ├── application_controller.rb
│ ├── concerns
│ └── curly_controller.rb
├── helpers
│ ├── application_helper.rb
│ └── curly_helper.rb
├── mailers
├── models
│ └── concerns
└── views
├── curly
└── layouts
In Listing 9.21 we told tree to only recurse down two levels; files
and directories that are deeper, such as those under the views/curly
directory, are not listed.
By default tree will list both files and directories. Often it is useful
just to see a list of directories without the files cluttering up the
tree. We can use the -d flag to print out just the directories.
$ tree -d
Listing 9.22
.
├── assets
│ ├── images
│ ├── javascripts
│ └── stylesheets
├── controllers
│ └── concerns
├── helpers
├── mailers
├── models
│ └── concerns
└── views
├── curly
└── layouts
So far we have been using tree to print out a listing of the current
directory, but like the ls command (Chapter 1 Section 1.3), we can
also give it a path to another directory.
$ tree -d /usr/local/etc/
Listing 9.23
/usr/local/etc/
├── ImageMagick
├── bash_completion.d
│ └── helpers
├── fonts
│ └── conf.d
├── openssl
│ └── misc
├── profile.d
└── rabbitmq
As we can see in Listing 9.23 we have printed out a tree listing of all
of the directories under my /usr/local/etc/ directory.
9.9 Wc
The wc command provides two really useful functions, it will both
count the number of words in a file, as well as the number of lines
in a file.
$ wc -w /usr/share/dict/web2a
Listing 9.24
121847 /usr/share/dict/web2a
As we can see in Listing 9.24 the /usr/share/dict/web2a file
contains 121847 words.
$ wc -l /usr/share/dict/web2a
Listing 9.25
76205 /usr/share/dict/web2a
Listing 9.25 shows that our file contains 76205 lines in it.
In the section on Ag/Ack 2.2, we saw how we could search for the
occurrences of “DHH” in the Rails source code. But what if we just
wanted to count the occurrences of the phrase “DHH” in the code?
Simple, we can accomplish that by piping the ag output into wc with
the pipe operator, |.
$ ag DHH | wc -l
The result of our search should look something like Listing 9.26:
Listing 9.26
26
1. Mark your calendars for August 24th, 2016, and make sure to send me a 40th
birthday greeting. :) ↑