Wednesday, April 2, 2014

Shell one-liner: Get your effective Ghostscript path

I amuse me.


gs -? | grep \/ | grep : | sed 's/\ //g' |  sed 's/:/\n/g' | grep -v ^$ | xargs ls -ld 2>&1 |  grep -v "No such" | awk '{print $NF}' | tr '\n' ':'

Ghostscript's helpfile mentions its font path.  However, it's not presented in a usable format, and worse, it includes directories that don't exist.  This cleans it up and spits it back out in a format that you can paste into a path configuration.

Saturday, March 29, 2014

Destroy a schema from the inside

Oracle does not provide a way for a user to pave over his own schema.  If you don't have dba privileges, this means you have to remove your schema by destroying each object.

This is a VERY rough recipe that I just wrote for a coworker.  It assumes you have Oracle SQLDeveloper and a shell handy.
  1. sql> select /*csv*/ 'DROP ',user_objects.object_type,' ',user_objects.object_name from user_objects where object_type in ('INDEX','TABLE');
  2. F5 (run as script)
  3. Select everything in your output window and copy it to /tmp/objects
  4. bash> cat /tmp/objects | grep -v OBJECT_NAME | sed s/\"//g | sed s/\,//g | sed s/$/\;/ > /tmp/drop.sql
  5. In SQLNavigator, clear your query and output screens (pencil eraser)
  6. File -> Open /tmp/drop.sql
  7. F5 (run as script) -- drops may cascade, which will cause errors later in the script; ignore
  8. sql> purge recyclebin;
  9. sql> select * from user_objects;  -- should return 0 rows now.
This can easily be adapted to whatever Oracle client and text editor you have handy.  In place of the seds and greps, use a basic text editor to remove the header line, remove all commas and quotes, and add a semicolon to each line.




Thursday, January 30, 2014

Awk: Print all but the last field

The other day I had a list of files, and needed to extract a list of the directories containing those files. So, in more general terms, I needed everything but the last field of each line.   That can be done in awk with

awk -F/ '{$NF=""; print $0}' filename 

i.e., you set the Nth field to null, then print the modified item.   You can do that with other fields as well -- $1, $(NF-1), and so on.

But that changes all the slashes to spaces. I knew there were no spaces in my list, so I fixed it with sed:

awk -F/ '{$NF=""; print $0}' filename | sed s/\ /\//g 

I could also have used the OFS (output field separator) directive in awk, but that doesn't work within a one-liner.

awk -F/ 'BEGIN { OFS = "/"}{ $NF=""; print $0 }' filename 

You can also edit the output record separator the same way -- for example, if you're sedawking a batch script, perhaps you want to add semicolons.

awk -F/ 'BEGIN { OFS = "/"; ORS=";\n"}{ $NF=""; print $0 }' filename 

 (h/t One Tip Per Day and GNU)

Thursday, August 8, 2013

Newbie help: Finding yourself (assuming you're a script)

Sometimes a script needs to figure out its own filename.  This is useful when creating error output and logs -- basically, anytime that the source of a chunk of output might be ambiguous.  This is done via basename:

myname = `basename $0`

Why basename $0?  If you think about handling arguments in shell scripts, you'll recall that the first argument is $1, the second is $2, and so on.  So the full pathname of the script is the zeroth argument.  Basename simply strips that string down to the filename.

To do the same thing, but get the containing directory instead, use

mydir = `dirname $0`

Easy enough.

Unfortunately, $0 only gives you the path of the script as it was run.  So if we do this:

cd /opt/somedir
./subdir/script.sh

then dirname $0 will only return ./subdir .  That's not useful if we need to change directories during the course of script.sh without losing track of where we started.

Here's the solution:

SCRIPTPATH=$( cd "$(dirname "$0")" ; pwd -P )

Spawn a subshell, cd into the directory using the relative or absolute path from dirname $0, and then print the working directory of the subshell.  This version resolves symlinks; omit the -P to preserve them.

(This post is mostly an excuse to write that last trick down.  Thanks to the folks on this post for coming up with it.)

Wednesday, May 8, 2013

Newbie help: find basics

The find command is a general file-finding utility with much a much broader range of talents than locate.  Find starts from a given directory and locates all files below that directory that meet specified constraints.  You can look for files by name (or regex), size, age, ownership, permissions, or any combination.

Find has built-in actions, such as delete, ls, print[ to file], and exec[ute-another-command].  You can also pipe the output into other commands.  I'll cover actions in a later post.

Basic syntax:
find path -constraint value

Add as many constraints as you like.   Any flag can be negated with a bang; see the very last examples for the syntax.

The most common constraints are size, and modified date (-mtime).  Both of these flags can serve as an upper or lower bound.

Example:  Which files below the current directory are less than five days old and more than 5kb?  Which are more than five days old and less than 5kb?

find . -mtime -5 -size +5000
find . -mtime +5 -size -5000

The -type flag allows you to specify whether you're looking for files or directories.  By default, find returns both.  Depending on your OS, the values will be either "f" or "file", and either "d" or "dir".  Check man for details.

The -name flag can take a full case sensitive filename, or a regex pattern.  If you use a pattern, enclose it in double quotes.

find /app -name applog
find /app -name "*log"
find . -name "*dunno*"
find . -name "[j,J]ava*"

Find can also identify files owned by a specific user or group.  (This flag is available on OS X, but doesn't appear to work.)

find /tmp -user kexline

Combine flags to ask real-world questions about your files.  Example:  What largish, non-gzipped  files did I create in my application directory since this time yesterday?

find /app -type f -mtime -1 -user kexline -size +100000 ! -name "*gz"

As promised, there's a bang negation.  Any flag can be prepended with a bang to reverse its meaning.  What files did all the other non-root users create yesterday, anywhere on the machine?

sudo su 
find / -type f -mtime -1 ! -user kexline ! -user root 

Newbie help: The "locate" command

Some *nixes, including Centos and Red Hat have an indexed finder utility called locate.  It's a very limited tool, but when you know what you're looking for, it can be the quickest way to find a file.

Basic usage:
locate [-i insensitive, -w wholename] a-filename-substring

It will generally return too much info, so grep for other known substrings to pare down the results.

Example:  I know exactly what file I want, but where did I put it?
$locate iCanHasPortlet.war
/app/liferay/iCanHasPortlet.war

Example:  I only know bits of a ridiculously long filename, what was it?
Mac:~ kexline$ locate -i license | grep -i prod | grep -i acme
/Users/kexline/Documents/liferay/licenses/license-production-production-5.6sp3-acmecomputercompany-main.xml

If locate doesn't cough up the goods, then your index is probably older than the desired file.  (Locate is not useful for new files; but then again, if something is very new you should know what or where it is.)  On RH/Centos, become root, run updatedb & , and get some coffee. 

Newbie help: Is this file in use?


You can use "fuser" to check whether any processes have a file open.

$ fuser somefile 
somefile:        20719
$ fuser anotherfile
$

Pid 20719 is using somefile, but nothing is using anotherfile.

Pipe queen bonus:  I want to compress some old stuff in a directory.  Here are some big files:
$du -sk ./* | sort -n | tail -5
71796 ./applog.20120418.gz
349252 ./applog
422952 ./applog.20120613
598672 ./applog.20120627
2816980 ./applog.20130204

Which of the largest five files are in use, if any?
$du -sk ./* | sort -n | tail -5 | awk '{print $2}' | xargs fuser
./applog:      44827

Pid 44827 is using the current applog.  The last three are safe to compress.

(Tangent:  Compression generally writes to the current filesystem.  Therefore, you can't compress in a filesystem that's 100% full.)