Thursday, July 13, 2006

Using ImageMagick and 4NT to find jpegs by quality level

Using ImageMagick and 4NT to find and modify all jpegs in the current dir who have quality level 94:

for %f in (*.jpg) do (echo %f
    & identify -verbose %f | grep Quality
    | grep -o "[0-9]*")


iff "%@execstr[identify -verbose %f
    | grep Quality | grep -o "[0-9][0-9]"]" == "94"
    then & echo %f & endiff


for %f in (*.jpg) do
    (iff "%@execstr[identify -verbose %f
    | grep Quality | grep -o "[0-9][0-9]"]" == "94"
    then & echo %f &
    mogrify -strip -quality 84 %f & endiff)




Unrelated side note:
This is one of several posts that I will be making in the near future, which come directly from my ever-growing toblog.txt file... No code cleanup or lengthly explanations, just commands I've run at some point that I thought were worth saving.

Wednesday, July 05, 2006

Bash history substitution

Anyone who has had an introductory unix course should know about the bash shell's "history" command, which gives you a numbered list of commands that you've run previously.

You can execute one of those commands again by doing:
$ ![number] (for a particular command you've seen on the history list)
or
$ !! (for the previous command/last command in the history list)


One thing that I didn't learn in any class, but did find out about from a co-worker, several years ago, was history substitution. It's easy to run the previous command with minor changes, by using a caret-delimited substitution expression. Here's a very simple example:

view a file:
$ cat spugbrap.txt

then, edit that same file:
$ ^cat^vim^

that gets expanded to (and executed as):
$ vim spugbrap.txt


I've used this feature countless times since learning about it, but it always suffered from a limitation: If the pattern you're trying to match occurs multiple times in the previous commandline, this subtitution method only replaces the first occurrance of it. So, I recently decided to find out how to substitute multiple occurances, since I was sure there had to be an easy way. Here's one way I found:

watch a couple of tomcat log files continuously:
$ tail -F ~/tomcat/logs/stdout_20060704.log ~/tomcat/logs/stderr_20060704.log

The next day, the log file names are different, because they're date-based. so I want to change 20060704 to 20060705, and it needs to happen twice because the date occurs twice in that commandline. No problem! Assuming the previously executed command was the "tail" commandline, above, simply enter this:
$ !!:gs/20060704/20060705/

that gets expanded to (and executed as):
$ tail -F ~/tomcat/logs/stdout_20060705.log ~/tomcat/logs/stderr_20060705.log


What if my previous command was long, and I need to make multiple substitutions with multiple strings?

previous command:
$ tail -F stdout_20060704.log stderr_20060704.log host-manager.2006-07-04.log catalina.2006-07-04.log admin.2006-07-04.log localhost.2006-07-04.log manager.2006-07-04.log jakarta_service_20060704.log

to change the dates, which occur in two formats:
$ !!:gs/20060704/20060705/:gs/2006-07-04/2006-07-05/


If the command I want to run (with substitutions) was not the previous command, but some other command that appears in the numbered list from running 'history', put the history line number between the exclamation point and the colon:
$ !123:gs/oldstr/replacementstr/


For more information about this, and other bash history manipulation capabilities, check out:
Bash Features - Using History Interactively

Wednesday, June 28, 2006

Making System.out.println() return a String

At some point, recently, I needed to do both of these things in one little Java expression:
- output a String to stdout
- return the same String

System.out.println() returns 'void', and you can't cast void to String, so I struggled with this for a little while. Here's what I came up with (download here if it looks ugly in the blog):

public class VoidToString
{
  public static void main(String[] args)
  {
    System.out.println("returned value: [" +
      new Object()
      {
        public String q(String p)
        {
          System.out.println("stdout: [" + p + "]");
          return p;
        }
      }.q("blah") + "]");
  }
}


It ended up not working in the context I was trying to use it in, because the 3rd-party API I was using did not appreciate the inner class, but I still thought it was a neat little trick.