|
|
slmingol posted this in tips & tricks on November 9th, 2009, @ 10:45 am
Background
Before my wife and I had kids we thought it would be nice to collect the United States quarters that were released during 1999 through 2008 to commemorate each of the 50 states. Seemed like something simple to do and would be a nice gift for the kids when they got older. So we bought a couple of the blue books which you can fill up with quarters as you find them. Each book contains 100 slots, 2 for each state. One slot is for the Philadelphia minted version of the quarter, and the other slot is for the Denver mint.
Problem
Well we ended up having 3 kids so we have to collect 300 quarters. The task of finding the quarters has been more of a dad task so when I have a chance, I’ll put a $5 dollar bill in various soda machines at work and go quarter fishing. This approach has been working fairly well and we’ve collected ~130 of the 300 quarters thus far.
However I’ve started getting to the point where I’m netting a lot of duplicates and the job of having to bring them home to weed through them is starting to get old. Having a list of which quarters we already have would sure be nice, so I could quickly nix any duplicates.
Solution
Of course I wanted a low tech solution, i.e. a piece of paper in my wallet would do the job, but how to do it?
The answer? A text file that I could maintain would suffice. No need for a bloated spreadsheet or some fancy handheld app. So I created a file, quarters.txt, like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| State Year Cnt (P/D)
===== ==== =========
Alabama 2003 2/1
Alaska 2008 3/1
Arizona 2008 3/0
Arkansas 2003 3/0
California 2005 3/0
Colorado 2006 3/0
Connecticut 1999 3/2
Delaware 1999 0/0
Florida 2004 2/0
Georgia 1999 2/1
Hawaii 2008 3/0
... |
It’s about as simple a text file as you can get. 3 columns, State, Year, and Counts. The 3rd column shows how many P and D quarters I have for a given state. So for example, for Alabama, I’ve got 2 Philadelphia minted quarters, and 1 Denver minted.
So you’re probably wondering, “why the hell is this guy writing up this in a blog post?”
We’ll the interesting bit to this low tech solution is how I print this list out. For this task I make use of a pretty powerful UNIX command called enscript, which lets you do all kinds of nifty things to a text file to augment how it looks when it gets printed.
About the only thing enscript doesn’t do for you, is give you the ability to preview your text file prior to printing. To accomplish this bit, I made use of another powerful UNIX command called ps2pdf. This command will take a postscript file (ps) and convert it to a pdf file.
So putting all the pieces together I came up with the following command:
1
| enscript --fancy-header -U 4 quarters.txt -o - | ps2pdf - quarters_sm.pdf |
The first part of this command, will call enscript instructing it to convert the file quarters.txt, and print it to standard out -o -. The printout will include some fancy headers and enscript will print the text file out in what is called 4 UP. This means that 4 pages will be printed on a single piece of paper. You could also print the page out in 2 UP, 8 UP, etc. It only needs to be a power of 2. BTW, 2 and 4 are the most commonly used, 8 is pretty hard to read.
The second part of this command passes the postscript generated by enscript through a UNIX pipe which gets picked up by ps2pdf, and converts it into a PDF file, quarters_sm.pdf.
From here you can check what the page would look like using your favorite PDF viewer, such as evince or xpdf. Once you’re comfortable with the page you can actually print it out from the PDF reader, or via the command-line.
…. Continue reading → [one-liner]: Previewing a Pretty Printed Text File using enscript & ps2pdf »»
slmingol posted this in tips & tricks on October 15th, 2009, @ 10:13 am
Background
From time to time I need to move and/or copy a subset of files from one directory to another. I typically would use something like one of these to do the task:
1
2
3
4
5
| #-- COPY
find . -type f -ctime -1 | xargs -I {} cp {} /some/other/directory
#-- MOVE
find . -type f -ctime -1 | xargs -I {} mv {} /some/other/directory |
NOTE: The 1st command finds all the files in the current directory that are less than 24 hours old, and copies them to /some/other/directory. The 2nd command finds all the files in the current directory that are less than 24 hours old, and moves them to /some/other/directory.
But then I realized that by using xargs’ –I switch I was basically limiting xargs to doing a single file at a time. According to xargs’ man page, when you use the –I switch you’re implying the –x switch AND the –L 1 switch. The L switch is what tells xargs how many lines of input to process at a time, so we’re basically telling it to only handle one file at a time. This made no sense. I was unintentially limiting xargs’ ability to optimize the command-line. So I found a better way.
New Approach
By utilizing 2 little used switches (–t | ––target-directory) on cp and mv I could un-tie xargs’ hands.
copy
1
2
3
4
5
| # long form
find . -type f -ctime -1 | xargs -0 cp --target-directory=/some/other/directory
# short form
find . -type f -ctime -1 | xargs -0 cp -t /some/other/directory |
move
1
2
3
4
5
| # long form
find . -type f -ctime -1 | xargs -0 mv --target-directory=/some/other/directory
# short form
find . -type f -ctime -1 | xargs -0 mv -t /some/other/directory |
NOTE: For further details regarding my one-liner blog posts, check out my one-liner style guide primer.
slmingol posted this in tips & tricks on October 1st, 2009, @ 10:35 am
Problem
Recently at my day job I’ve been having to go through some pretty old Bash scripts that I’ve basically inherited. As I’ve been going through them I’ve been seeing a lot of confusion as to the proper use of Bash’s export command. The major offense? Not really understand whether a particular variables needs to be exported, or not. So I thought I’d take a moment just to clarify when and when not to use export.
The export command has really only one true purpose. To mark and/or unmark variables (and functions) that you want to have automatically exported to environments of subsequently executed commands. So if you create a script that calls other commands, and you want to push variables into the environment of these commands, then you’ll want to use export.
Example #1 (without export)
For example, let’s say we have the following 2 scripts:
1
2
3
4
5
6
7
| #!/bin/bash
# script #1: parent.bash
var1="this was set by the parent shell script"
echo "inside $0 script: $var1"
./child.bash |
1
2
3
4
| #!/bin/bash
# script #2: child.bash
echo "inside $0 script: $var1" |
And when I run the script parent.bash I get this output:
1
2
3
4
5
| # output from parent.bash & child.bash (without export)
% ./parent.bash
inside ./parent.bash script: this was set by the parent shell script
inside ./child.bash script: |
Notice how the variable $var1, which was set in the parent.bash script, didn’t get displayed by the child.bash script? Now watch this example with the variable $var1 exported in the parent.bash script.
Example #2 (with export)
1
2
3
4
5
6
7
| #!/bin/bash
# script #1: parent.bash
export var1="this was set by the parent shell script"
echo "inside $0 script: $var1"
./child.bash |
1
2
3
4
| #!/bin/bash
# script #2: child.bash
echo "inside $0 script: $var1" |
And when we run parent.bash
1
2
3
4
5
| # output from parent.bash & child.bash (with export)
% ./parent.bash
inside ./parent.bash script: this was set my the parent shell script
inside ./child.bash script: this was set my the parent shell script |
Example #3 (un-exporting)
Export isn’t just a one trick pony. It can also unmark a previously exported variable.
…. Continue reading → [one-liner]: How to Use the Bash Shell’s export Command »»
slmingol posted this in tips & tricks on September 21st, 2009, @ 10:13 am
Background
I recently saw a post over on Linux Journal that discussed how to glean information about a system’s hard drive, such as its serial number, without having to actually open up the case and physically check it. So I thought I’d take the opportunity to write up a blog post with the specifics of how to do this under Fedora & CentOS, just so I’d have this info handy for future use.
BTW, I was able to accomplish this task several different ways, so this post will cover all the different ways that I could get this info.
Command #1: lshw
This is probably the best tool for getting at a system’s internals. First make sure it’s installed.
For our example you would run the command lshw -class disk:
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
| % lshw -class disk
*-disk
description: ATA Disk
product: HTS726060M9AT00
vendor: Hitachi
physical id: 0
bus info: scsi@0:0.0.0
logical name: /dev/sda
version: MH4O
serial: MRH403M4GS551Y
size: 55GiB (60GB)
capabilities: partitioned partitioned:dos
configuration: ansiversion=5 signature=cccdcccd
*-cdrom
description: DVD reader
product: UJDA755yDVD/CDRW
vendor: MATSHITA
physical id: 1
bus info: scsi@1:0.0.0
logical name: /dev/cdrom
logical name: /dev/cdrw
logical name: /dev/dvd
logical name: /dev/scd0
logical name: /dev/sr0
version: 1.71
capabilities: removable audio cd-r cd-rw dvd
configuration: ansiversion=5 status=nodisc |
The first section that’s returned is called -disk. Here’s you’ll see the vendor: Hitachi, the product number, HTS726060M9AT00, and my serial number: MRH403M4GS551Y.
Command #2: smartctl
The next tool that would give this type of info is called smartctl. It’s a tool that’s part of the smartmontool package. You may be familiar with the acronym S.M.A.R.T.. The acronym stands for: Self-Monitoring, Analysis, and Reporting Technology. This is a standard that most modern disks have in which vital statistics about a disk drive are provided through a standard API. Here’s how to install it.
1
| yum install smartmontools |
…and once installed you can use the bundled in tool smartctl like so:
…. Continue reading → [one-liner]: Determining a Hard Drive’s Manufaturer Under Fedora 10 & CentOS 5 »»
slmingol posted this in tips & tricks on September 5th, 2009, @ 1:13 am
As it is with UNIX & Linux there is always another way. In my previous article [one-liner]: Filtering ps from ps, one reader, Christoph, mentioned an alternative method to the one I outlined. In this case, I would consider his to be a better way, so I thought I would take a second to demonstrate this alternative method. The alternative? Use the command pgrep.
The Original Approach
My original post offered the following one-liner:
1
2
3
4
5
6
7
8
9
10
| % ps -eaf | grep "[h]ttpd"
root 2683 1 0 2008 ? 00:20:31 /usr/sbin/httpd
apache 17146 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17147 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17149 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17150 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17151 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17152 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17153 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17154 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd |
This one-liner provided a list of all the httpd processes running, while filtering out the actual string from the grep httpd command.
The Alternative Approach
By using the command pgrep, the same effect can be achieved and a lot more. For starters, you can get a list of all the httpd PIDs:
1
2
3
4
5
6
7
8
9
| # list of httpd PIDs
% pgrep httpd
1608
7645
9739
10051
27712
27859 |
This could be useful in a shell script, if needed, to check for any running httpd processes. For example:
1
2
3
4
| # test for httpd processes
% [ -z "`pgrep httpd`" ] || echo "running"
running |
Here are some other examples:
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
| # list of PIDs with corresponding command name
% pgrep -l httpd
1608 httpd
7645 httpd
9739 httpd
10051 httpd
27712 httpd
27859 httpd
# list of PIDs with corresponding command name owned by user root
% pgrep -l -u root httpd
1608 httpd
# list of PIDs, separated with a comma delimiter
% pgrep -d, httpd
1608,7645,9739,14119,14162,27859
# detailed list of httpd PIDs via ps
# NOTE: $(...) runs the command above, returning the list of PIDs to ps
% ps -fp $(pgrep -d, httpd)
UID PID PPID C STIME TTY TIME CMD
root 1608 1 0 Aug03 ? 00:00:05 /usr/sbin/httpd
apache 7645 1608 0 Sep04 ? 00:00:47 /usr/sbin/httpd
apache 9739 1608 0 Sep04 ? 00:01:50 /usr/sbin/httpd
apache 14119 1608 0 Sep04 ? 00:00:13 /usr/sbin/httpd
apache 14162 1608 0 Sep04 ? 00:00:13 /usr/sbin/httpd
apache 27859 1608 0 Sep04 ? 00:07:19 /usr/sbin/httpd |
Thanks again to Christoph for pointing out this alternative.
NOTE: For further details regarding my one-liner blog posts, check out my one-liner style guide primer.
slmingol posted this in tips & tricks on September 4th, 2009, @ 1:13 pm
Background
This is a pretty handy trick to know when you want to filter out the command you’re running, so that it’s not included in ps output. This proves handy when writing a shell script that needs to parse output from ps.
NOTE: The command ps, allows you to see all the processes being run on a UNIX/Linux system. You typically use it with the switches “-eaf” or “-ef”.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # columns description:
# UID = user who owns the process
# PID = process #
# PPID = parents' process #
# C =
# STIME = start time
# TTY = terminal type (has to do with which shell command ran from)
# TIME = system time its run
# CMD = command (aka. program name)
% ps -eaf
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 2008 ? 00:24:46 init [5]
root 2 0 0 2008 ? 00:00:00 [kthreadd]
root 3 2 0 2008 ? 00:01:58 [migration/0]
root 4 2 0 2008 ? 00:23:13 [ksoftirqd/0]
root 5 2 0 2008 ? 00:00:00 [watchdog/0]
root 6 2 0 2008 ? 00:02:35 [migration/1]
root 7 2 0 2008 ? 00:09:55 [ksoftirqd/1]
root 8 2 0 2008 ? 00:00:00 [watchdog/1]
root 9 2 0 2008 ? 00:06:36 [events/0]
root 10 2 0 2008 ? 00:06:16 [events/1]
root 11 2 0 2008 ? 00:00:10 [khelper]
root 54 2 0 2008 ? 00:19:26 [kblockd/0] |
Problem
Here’s an example where we want to see if a program is running, so we grep the output of ps like so:
1
2
3
4
5
6
7
8
9
10
11
| % ps -eaf | grep httpd
root 2683 1 0 2008 ? 00:20:31 /usr/sbin/httpd
user1 13188 3984 0 12:45 pts/1 00:00:00 grep httpd
apache 17146 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17147 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17149 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17150 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17151 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17152 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17153 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17154 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd |
The problem? Notice that a portion of our command, “grep httpd” is polluting our ps output. How can we get rid of it?
The Trick
You can alter what you are grepping for, without actually altering the results, by using a benign regular expression.
1
2
3
4
5
6
7
8
9
10
| % ps -eaf | grep "[h]ttpd"
root 2683 1 0 2008 ? 00:20:31 /usr/sbin/httpd
apache 17146 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17147 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17149 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17150 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17151 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17152 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17153 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd
apache 17154 2683 0 Aug30 ? 00:00:02 /usr/sbin/httpd |
Explanation
…. Continue reading → [one-liner]: Filtering ps from ps »»
|