Expanding your bash knowledge and .bashrc file with some sweet tips

I always thought commandlinefu.com had a nice repository information related to bash and your .bashrc files. as you can see from my dotfiles I’ve used different functions. There is a lot to learn here and create a .bashrc tailored to your use. Personally, I like to put additions into my .bash_aliases file as you can see in my github.

Some great functions and bash usage there make the site well worth reading and incorporating into your bash usage. My dot files aren’t perfect but I know I’ll always be looking to improve them. If you’re in the same boat check out the list above and start getting into hosting your dotfiles on github.

For more information about dotfiles, check out github’s notes on dotfiles. Very smart and convenient way to have access / maintain your dotfiles. It’s always going to be a strive for perfection but these community based resources help you get started.

If I were to migrate to zsh, that’s a different story but we’ll worry about that as it comes. Good lucky, happy hacking. Happy Holidays and a Merry Chirstmas.

What I find most annoying about WordPress

I like WordPress when you take all the features, the community, the plugins, themes and documentation (codex) into consideration.

There has always been one thing that really bothers me (I have plenty more) and that’s how it databases some information. Creating a “database” inside a database is generally frowned upon. In this instance, WordPress uses PHP serialization, which allows you to save a PHP array in the database. The issue resides in replacing database references.

If you were to have:

string(38) "C:3:"obj":23:{s:15:"My private data";}",

replacing strings without the exact number of characters could cause something to break (due to improper unserialization). There are a lot of blogs that say, “take your SQL file and “find/replace” “mysite.com” with “mylivesite.com” — this can break or disregard plugin settings you’ve worked so hard on. This is because of the difference in length. “15″ = “My private data”

$ echo -n "My private data" |wc -c
15

Replacing the length of the string, doesn’t replace that integer count.

It’s pretty deep in the code and relied by a lot of functions in the wp-core. I don’t believe changing it would be an easy process. Knowing this, if you wanted to put a “database” inside a database, perhaps JSON is a better option.

There are premium and free (hacky) versions to proper unserialize, change and reserialize your data (nothing I can point you to at the moment. The awareness that this is a case is something you should consider however.

I’ll give more details and outline other shortcomings and work-arounds in the near future. Cheers.

wp-cli – A command line interface for WordPress

I came across wp-cli, which is a Command Line Interface (CLI) to WordPress (WP).

There is a lot of out of the box functionality, with a blossoming community putting together “recipes,” or cookbooks in an effort to reduce tedious tasks you might normally do through the GUI. Using the CLI, enables you to script, or automate processes. This is great for web developers, and system administrators, amongst others.

I think the project summarized their tool set well in the following quote:

WP-CLI is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser.

Browsing through the commands can give a basic idea of what tasks might be better scripted. Certainly a time-saver if applied correctly.

The anatomy of a “command” is broken down on wp-cli github.com wiki which also links to other projects they may spark interest or be of direct use.

I’ve got a few application ideas in the conceptualization phase myself. I hope to write back more in regards to this tool in the future.

Readers, have you any advice, favorite applications, or alternative implementations worth looking into?

Having fun with sed, easter eggs, hidden in plain view

Introduction

I was fooling around, practicing my bash skills and encoded a little something when I was writing a set of helper scripts in bash for Nexuiz (now forked to Xonotic). At line 406 in my github repository for NDT you’ll see I’ve left a harmless easter egg. Acknowledged in the case switch at line 683:

--nothing_to_see_here|--moo) moo;;

Paying homage to the “apt-get” “moo” command easter egg, in some regards.

Make the cow say moo

2013-09-27-172121_640x222_scrot

echo -e 'VAAAAAZBVmKKVCZVDDDDDZVVVVVVVVEVVVGAAGZVVVVVVVVVEVVHKKIEAAAAAAAZVVVVVVVVVVVVHAAIEVVVVVVVIEFEZVVVVVVVVVVVVVVVVJJDDDDwVJZVVVVVVVVVVVVVVVVJJVVVVVJJZ' | sed 's/A/_/g;s/B//g;s/D/-/g;s/E/\\/g;s/F/\//;s/G/\^/g;s/H/(/g;s/I/)/g;s/J/|/g;s/K/o/g;s/V/ /g;s/Z/\n/g'

I know encoded strings look scary but this is an echo, so you should know it can’t harm your computer. The is a “poor man’s encryption” at best. It’s obfuscating the original cow output and using sed pattern replacements to revert back to the ASCII art it once was.

Further Breakdown

An example within the massive sed string of replacements, is one targeting the character “Z” to replace with “newline escape character, \n.”

s/Z/\n/g

I will blog more about sed in the future. It’s a wonderful tool available in most *nix systems. The name is derived from stream editor, it’s taking a stream of output and editing before outputting.

Using WordPress Language Files to Spice Up Copy or Add HTML

Introduction

Editing the core files of WordPress is an obvious no-no for any competent developer. It will make upgrades more of a task than they need to be and it isn’t very portable. Using the WordPress plugin system is one way to overcome the issue of extending the core, but what about rewriting language on the forgot password form or displaying more details in error messages? Using language files, we can overcome this and even inject our own HTML.

WordPress Language Files

To learn about the way language files work in WordPress, first I needed to get a briefing in localizing WordPress. Which basically consist of two generated files (.po and .mo) where po is plaintext and mo is a compiled (machine code) version of the plaintext that will run faster at runtime. They work by hooking into functions defined by the English language (i.e. __(“Forgot Password”)), so no English po/mo files exist.

I had to learn how to create POT files. So I grabbed a fresh copy of WordPress, ran in through poedit:

sudo apt-get install poedit

Loosely following this excellent blog post, how-to translate a wordpress theme.

English WordPress 3.x Language Files (po/mo)

WordPress uses “gettext” to handle translation as described in the “briefing” link above.

These concepts work at the plugin level too. If there are language folders with .pot files, you can generate your own .mo file and change copy. In some instances you may want to develop a patch or give in touch with the developer of a plugin to allow for more flexibility in customized language through the back-end which would store a string in the database rather than a language file but generally speaking, generating your own lang file isn’t a problem.

The caveat here is that when you upgrade the plugin, you may have to regenerate the language.

Further Reading

Learn more about i18n (internationalization) for WordPress.

I meant to post this months ago and never finished up the article but the question come up again recently at work. Please let me know if you need clarification on anything by asking questions in the comments. You can also email me: [email protected]

/bin/rm: cannot execute [Argument list too long]

The Basics

If you’ve ever come across this error, you likely had too many files in your folder. Opening the folder in a GUI is futile. What do you do? One solution would be to remove “chunks” of files at a time. That’s silly though, we like too keep things simple, right?

If this isn’t working:

rm -rf *.jpg

And you’re getting the error:

/bin/rm: cannot execute [Argument list too long]

Try using the “find” command with the “-exec” flag as such:

find -iname "*.jpg" -exec rm -rf {} \;

Note (I use “-iname” instead of “-name” out of habit. “-iname” merely means “case-insensitive” but it could be considered superfluous if I know all the extensions are lowercase.

More Tips

In another terminal I was able to verify the files were being removed by using “ls” (list files) piped (|) to the “wc” (word count) with the “-l” (lines) flag.

ls |wc -l

Feeling lasy? use “watch” to let the command repeat itself.

watch "ls |wc -l"

The command, “find,” is an awesome tool, which I’ve mentioned in other bash related posts on my blog.

man find

Feel free to ask questions in the comments.

Mr. Bougo has added great information on the behavior of “find” and other commands in the comments below. Certainly worth reading.

Creating high quality thumbnails for PDFs in Linux using Imagemagick

If you’ve been googling for a solution to this, you might have found the quality of your pdf thumbnails images created using imagemagick is less than what you’ve desired. There is a simple but not exactly straightforward reason for this. Imagemagick uses ghostscript to generate these thumbnails from pdfs, unless you specify the density before the filename, you may end up with poor quality thumbnails. I’ve used my resume to demonstrate.

# Create [a low quality] thumbnail image for the first page from a pdf
f="tyler.mulligan-resume-winter-2013.pdf"; convert $f[0] -quality 100 -resize 960x +adjoin $f-%02d.png
# Create [a high quality] thumbnail image for the first page from a pdf
f="tyler.mulligan-resume-winter-2013.pdf"; convert -density 300 $f[0] -quality 100 -resize 960x +adjoin $f-%02da.png

The difference in these thumbnails is minor but enough to drive a graphic designer insane. The font kerning is off and the shapes rasterize imperfectly.

Low Quality

tyler.mulligan-resume-winter-2013.pdf-00

High Qualitytyler.mulligan-resume-winter-2013.pdf-00a

I used the bracket page notation to define the first page of the pdf in the last two commands, filename.pdf[0] (zero index). It’s possible to do the entire PDF at once by removing it.

# Create high quality thumbnail images for a pdf
f="my.pdf"; convert -density 300 $f -quality 100 -resize 960x +adjoin $f-%02d.png

We can toss this in a for loop to perform the operation on a bunch:

# Create high quality thumbnail images from multiple pdfs
for f in *.pdf; do convert -density 300 $f -quality 100 -resize 960x +adjoin $f-%02d.png; done

If you’re still having issues with quality, you can play with the the -scale parameter, adding it after the -quality setting, i.e. “-scale @1500000″.

jQuery and jQuery UI in your Grease Monkey scripts.

Not all websites are made equal. Unfortunately, some of those websites are ones we’re required to use. Be it our job, our interests or the undiscovered, web-browsing can be the orgeon trail of the internet. Cultivating the atmosphere to work for us and bringing the right tools along for the journey are essential for survival, if you’re a pioneer.

I’m tired of websites that don’t provide, can’t provide or will never provide. I’ve called in my boys, Stylish and Grease Monkey on the front lines. However, beyond the crazy happenstance that another user might share a solution to your issue on userstyles.org or userscripts.org you could be left in the cold, without the right tools. I won’t go into detail on Stylish in this post but you might not even need it after you see the script.

Since I’m already connected with Google every which way in my life, why not pretend like the Internet is a big party and websites are your friends. Introduce jQuery from Google’s CDN to other friends (websites) that don’t already know jQuery and jQuery UI and make it personal.

That was the driving force behind this Grease Monkey Script, which was derived from mashing together strd6′s script and Joan Piedra’s script with an update to the latest versions of jQuery and jQuery UI.

// ==UserScript==
// @name           jQuery and jQuery UI
// @author         Tyler "-z-" Mulligan
// @version        0.5
// @namespace      http://www.doknowevil.net
// @description    jQuery 1.6.2 and jQuery UI 1.8.4 loaded from google's CDN with redmond theme.
// @include        http://www.website.com/*
//
// @resource       jQuery               https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
// @resource       jQueryUI             https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js
//
// @resource       jQueryUICSS          http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/jquery-ui.css
//
// @resource       ui-bg_inset-hard_100_fcfdfd_1x100.png  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png
// @resource       ui-bg_gloss-wave_55_5c9ccc_500x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png
// @resource       ui-bg_glass_85_dfeffc_1x400.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png
// @resource       ui-bg_glass_75_d0e5f5_1x400.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png
// @resource       ui-bg_inset-hard_100_f5f8f9_1x100.png  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png
// @resource       ui-bg_flat_55_fbec88_40x100.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png
// @resource       ui-bg_glass_95_fef1ec_1x400.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png
// @resource       ui-icons_469bdd_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_469bdd_256x240.png
// @resource       ui-icons_469bdd_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_469bdd_256x240.png
// @resource       ui-icons_d8e7f3_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_d8e7f3_256x240.png
// @resource       ui-icons_6da8d5_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_6da8d5_256x240.png
// @resource       ui-icons_217bc0_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_217bc0_256x240.png
// @resource       ui-icons_f9bd01_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_f9bd01_256x240.png
// @resource       ui-icons_2e83ff_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_2e83ff_256x240.png
// @resource       ui-icons_cd0a0a_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_cd0a0a_256x240.png
// @resource       ui-bg_flat_0_aaaaaa_40x100.png         http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png
// @resource       ui-bg_flat_0_aaaaaa_40x100.png         http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png

// ==/UserScript==

var $;

// Inject jQuery into page... gross hack... for now...
(function() {
    if (typeof unsafeWindow.jQuery == 'undefined') {
        var head = document.getElementsByTagName('head')[0];
 
        var script = document.createElement('script');
        script.type = 'text/javascript';
 
        var jQuery = GM_getResourceText('jQuery');
        var jQueryUI = GM_getResourceText('jQueryUI');
 
        script.innerHTML = jQuery + jQueryUI;
        head.appendChild(script);

    }
    GM_wait();
})();
   
// Check if jQuery's loaded
function GM_wait() {
    if (typeof unsafeWindow.jQuery == 'undefined') {
        window.setTimeout(GM_wait, 100);
    } else {
        $ = unsafeWindow.jQuery.noConflict(true);
        addUIStyles();
        letsJQuery();
    }
}

function addUIStyles() {
    var head = document.getElementsByTagName('head')[0];
    var resources = {
        'ui-bg_inset-hard_100_fcfdfd_1x100.png': GM_getResourceURL('ui-bg_inset-hard_100_fcfdfd_1x100.png'),
        'ui-bg_gloss-wave_55_5c9ccc_500x100.png': GM_getResourceURL('ui-bg_gloss-wave_55_5c9ccc_500x100.png'),
        'ui-bg_glass_85_dfeffc_1x400.png': GM_getResourceURL('ui-bg_glass_85_dfeffc_1x400.png'),
        'ui-bg_glass_75_d0e5f5_1x400.png': GM_getResourceURL('ui-bg_glass_75_d0e5f5_1x400.png'),
        'ui-bg_inset-hard_100_f5f8f9_1x100.png': GM_getResourceURL('ui-bg_inset-hard_100_f5f8f9_1x100.png'),
        'ui-bg_flat_55_fbec88_40x100.png': GM_getResourceURL('ui-bg_flat_55_fbec88_40x100.png'),
        'ui-bg_glass_95_fef1ec_1x400.png': GM_getResourceURL('ui-bg_glass_95_fef1ec_1x400.png'),
        'ui-icons_469bdd_256x240.png': GM_getResourceURL('ui-icons_469bdd_256x240.png'),
        'ui-icons_469bdd_256x240.png': GM_getResourceURL('ui-icons_469bdd_256x240.png'),
        'ui-icons_d8e7f3_256x240.png': GM_getResourceURL('ui-icons_d8e7f3_256x240.png'),
        'ui-icons_6da8d5_256x240.png': GM_getResourceURL('ui-icons_6da8d5_256x240.png'),
        'ui-icons_217bc0_256x240.png': GM_getResourceURL('ui-icons_217bc0_256x240.png'),
        'ui-icons_f9bd01_256x240.png': GM_getResourceURL('ui-icons_f9bd01_256x240.png'),
        'ui-icons_2e83ff_256x240.png': GM_getResourceURL('ui-icons_2e83ff_256x240.png'),
        'ui-icons_cd0a0a_256x240.png': GM_getResourceURL('ui-icons_cd0a0a_256x240.png'),
        'ui-bg_flat_0_aaaaaa_40x100.png': GM_getResourceURL('ui-bg_flat_0_aaaaaa_40x100.png'),
        'ui-bg_flat_0_aaaaaa_40x100.png': GM_getResourceURL('ui-bg_flat_0_aaaaaa_40x100.png')
    };
    
    var style = document.createElement('style');
    style.type = 'text/css';
    
    var css = GM_getResourceText ('jQueryUICSS');
    $.each(resources, function(resourceName, resourceUrl) {
        console.log(resourceName + ': ' + resourceUrl);
        css = css.replace( 'images/' + resourceName, resourceUrl);
    });
    
    style.innerHTML = css;
    head.appendChild(style);
}

// All your GM code must be inside this function
function letsJQuery() {
    //alert($); // check if the dollar (jquery) function works
    //alert($().jquery); // check jQuery version
    $("
I'm in a dialog!
").dialog({ buttons: { "Ok": function() { alert("Ok"); }, "Cancel": function() { $(this).dialog("close"); } } }); }

I also wanted to use this script with Chromium browser, the open-source version of Google Chrome. I found the TamperMonkey Extension for Chrome. Stylish is also available for Chrome.

Generating CSS Based on Images, also SEO-Friendly

I’ve typed out a lot of CSS that’s focused on using a background image to replace text. I’ve been using a cross-browser CSS trick that’s SEO-friendly, I’m not sure if it’s documented anywhere. I came upon the solution myself when I was searching for a clever way to do this years ago and it’s become the standard method for me. However, I dislike the tedious task of typing out the CSS and referencing the image pixels and at work, I don’t want my developers wasting that time either.

I figured it’d be best to come up with a simple solution, so I started coding something out in bash and it worked:

#!/bin/bash
# css.sh - generate common css and html
# Tyler Mulligan ([email protected])
# Last Update: 02/16/2011
# MIT License

create_block_image() {
    feh -lr ${1:-.} | awk '{ print $3" "$4" "$8 }' | sed '1d' | while read l; do N=$((N+1));
        cbi_css $l
    done
    feh -lr ${1:-.} | awk '{ print $3" "$4" "$8 }' | sed '1d' | while read l; do N=$((N+1));
        cbi_html_a $l
    done
    feh -lr ${1:-.} | awk '{ print $3" "$4" "$8 }' | sed '1d' | while read l; do N=$((N+1));
        cbi_html_div $l
    done
}
cbi_css() {
    f=${3##*/}
    echo "#${f%.*} {
    display: block;
    background: url('$3') no-repeat 0 0;
    width: 0;
    height: $2px;
    padding-left: $1px;
    overflow: hidden;
}"
}
cbi_html_a() {
    f=${3##*/}
    echo "${f%.*}"
}
cbi_html_div() {
    f=${3##*/}
    echo "
" } s=$1; shift; case $s in --image-block|--cbi|-i) create_block_image $@;; *) help help;; esac

Which ouputs something like:

z@zygon:~/scripts/css$ ./css.sh -i img/
#dumbtubes-fav {
    display: block;
    background: url('img/dumbtubes-fav.png') no-repeat 0 0;
    width: 0;
    height: 14px;
    padding-left: 16px;
    overflow: hidden;
}
#submit_new {
    display: block;
    background: url('img/submit_new.png') no-repeat 0 0;
    width: 0;
    height: 106px;
    padding-left: 244px;
    overflow: hidden;
}
#dumbtubes-logo {
    display: block;
    background: url('img/dumbtubes-logo.png') no-repeat 0 0;
    width: 0;
    height: 70px;
    padding-left: 274px;
    overflow: hidden;
}
dumbtubes-fav
submit_new

To explain the way this CSS works, it uses the padding-left as the actual width, setting the width 0 and then pushes whatever content you have out of view using overflow:hidden to hit it from view. This makes it easy for search engines, keeping your HTML clean and CSS simple.

The bash script relies of “feh” a lightweight image viewer for linux that outputs a list of images and their dimensions. It also generates some sample HTML to quickly drop in and modify.

This is not an elegant solution and I’m not happy with the fact that it relies on feh. I’ve been slowly getting into python and I was amazed at how fast I was able to recreate this script in Python.

#!/usr/bin/python
# css.py - generate common css and html
# Tyler Mulligan ([email protected])
# Last Update: 02/17/2011
# MIT License
from PIL import Image
import sys
import os.path

CSS_FORMAT = """#%s {\n\
    display: block;\n\
    background: url('%s') no-repeat 0 0;\n\
    height: %spx;\n\
    width: 0;\n\
    padding: %spx;\n\
    overflow: hidden;\n\
}\n"""

HTML_A_FORMAT = """%s\n"""
HTML_DIV_FORMAT = """
%s
\n""" css="" html_a="" html_div="" for tf in os.listdir(sys.argv[1]): f = os.path.join(sys.argv[1],tf) if os.path.isfile(f) == True : img = Image.open(f) fid = os.path.splitext(tf)[0] (width, height) = img.size[0:2] css += CSS_FORMAT % (fid,f,height,width) html_a += HTML_A_FORMAT % (fid,f,fid,fid) html_div += HTML_DIV_FORMAT % (fid,fid) print css print html_a print html_div

This is just the basic idea, I didn’t spend more than 15 minutes on this rewrite, it does what I need it to do so far. It was suggested by friends if I make it any bigger, to look into a templating engine, such as mako. I hope this script can be useful to someone :). PS, HTML_DIV_FORMAT should be on one line, not sure why my syntax highlighter is trying to put it on 3.