Creating an Array in Bash from a File With Each Element on a Separate Line

Let’s say that you have a file and you would like to convert each line in the file to an element in an array.

The key to this is knowing about and how to manipulate the IFS (Internal Field Separator).  The default IFS is whitespace (a space, tab, or newline) and if you create an array passing it a whitespace delimited list of strings, each token will be set to an element in the array.

ARRAY=(a b d c)

Will result in an array with a single letter in each element.

To do the same thing with the contents of a file, whereby each element is on a separate line, the first thing to be done is to set the IFS that is just new-lines (carriage returns).  Then set, as the input for the array, the contents of the file.

# Save our existing IFS
OIFS="$IFS"

# Set our IFS to a new-line/carriage return
IFS=$'\r\n'

# Create the array with the contents of a file
TEST_ARRAY=($(cat some_file.txt))

# Reset our IFS
IFS="$OIFS"

for i in "${TEST_ARRAY[@]}"
do
   echo $i
done

Removing The Last N Character From a String in Bash Script with sed

Here is a quick one-liner for trimming a specific number of characters from the end of a string under bash:

# Remove the last 5 characters
$ echo "somestringwith12345" | sed "s/.....$//g"
$ somestringwith

# Remove the last 3 characters
$ echo "somestringwith12345" | sed "s/...$//g"
$ somestringwith12

Splitting a String in Bash on the FIRST Occurrence of a Character

About a year ago I posted an article about how to split into an array of values based on a given delimiter in bash.

The following is how to take that same string and split it on the first occurrence of the same user defined delimiter.

Both use the ‘read’ command, but in a slightly different way.

Instead of passing read the -a [aname] parameter which tells it that “The words are assigned to sequential indices of the array variable aname, starting at 0.”, we pass is -r which indicates that “Backslash does not act as an escape character.  The backslash is considered to be part of the line.”.  This will make sure to include any backslash that is in the string in your output.

Then, we provide two variables into which we will store the split string.

#!/bin/bash

SOURCE_STRING='foo|blah|moo'

# Save the initial Interal Field Separator
OIFS="$IFS"

# Set the IFS to a custom delimiter
IFS='|'

read -r KEY VALUE <<< "${SOURCE_STRING}"
echo "KEY = $KEY, VALUE = $VALUE"

# Reset original IFS
IFS="$OIFS"

BASH Script With Default Arguments Defined in The Script

Often times you will want to write a BASH script where you don’t want to have to keep track of all of the positional command line arguments and/or you might want to configure it with a set of environmental variables while having a default value for each in the script.

Following is the syntax for declaring them in the shell script, and then an example on how to invoke it.

#!/bin/bash

: ${ARG1:="somedefault_arg1"}
: ${ARG2:="10"}

echo "ARG1 = $ARG1"
echo "ARG2 = $ARG2"

$ ./default-bash-vars.sh
ARG1 = somedefault_arg1
ARG2 = 10
$ ARG1="someOtherArg1" ARG2="20" ./default-bash-vars.sh
ARG1 = someOtherArg1
ARG2 = 20

In the example script, we have two variables, ARG1 and ARG2.  When running the script without providing any additional configuration the default values will be used.  When invoking it and defining the variables on the command line prior to executing the script those values will be used instead.

This prevents the situation where you potentially have many command-line arguments and then have to jugle the positional $1, $2, …. vars in the script.

Pin a “Show Desktop” Link to the Task Bar in Windows 7

To create a short cut and pin it to the task bar in Windows 7 do the following:

  1. Right-click on the Desktop and select New -> Shortcut.
  2. Enter the following in the field labeled “Type the location of the item:”  %windir%\explorer.exe shell:::{3080F90D-D7AD-11D9-BD98-0000947B0257}
  3. Click “Next” and name the shortcut and then click “Finish”.
  4. Update the icon so that you will recognize it when you pin it to the task bar.  To do so, right-click on the shortcut and select “Change Icon”
  5. Paste the following in the “Look for icons in this file”  %SystemRoot%\system32\imageres.dll
  6. Select an appropriate icon and click “Apply” and then “OK”.
  7. Right-click on the icon and select “Pin to Taskbar”.

Running Dynamically Generated Hive Queries From a Shell Script

If you want to write a HQL hive query and run it mulitple times from a shell script, each time passing it different data for the query, here is a quick example that should get you started.

The first thing to know is that by specifying n number of -hivevar key value pairs when invoking hive on the command line will allow you to pass that data into the hive process.

For example, if you do the following

$ hive -e 'SELECT * FROM some_table' -hivevar FOO=blah

You will have passed in a key of FOO with the value of ‘blah’ to the hive process.

A more practical example would be wanting to run the same hive query over multiple data partitions.

In this example, I’ve got a hive database that has a ‘packets’ table partitioned by hours which looks like 2014032601.

The hive query file (dest_ip_hive.sql) would look like:

SELECT packets.sourceip FROM packets
WHERE packets.destip = "${hivevar:DEST_IP}"
AND packets.hour = ${hivevar:HOUR}
GROUP BY packets.sourceip

And a shell script that would dynamically set those values for each invocation of hive would look like:

#!/bin/bash

#
# Destination IP that we are using to determine which
# packets we will examine.
#
DEST_IP="10.0.1.10"

for HOUR in 2014032209 2014032210 2014032211 2014032212
do

   echo "Running hive query for HOUR $HOUR"

   # Run a hive query from the command line setting variables that will be
   # expaned in the .sql file.
   hive -hivevar HOUR=$HOUR -hivevar DEST_IP=$DEST_IP \
   -f dest_ip_hive.sql > ${DEST_IP}-{$HOUR}.out

done

For each hour defined in the for loop, we will execute a hive command telling it to run the query contained in the file dest_ip_hive.sql.  The DEST_IP and HOUR variables that will be expanded in the query are passed to hive via the

-hivevar HOUR=$HOUR -hivevar DEST_IP=$DEST_IP

part of the hive command.  And the output for each query will be written to a different file for each query.

Eclipse Android Development Error executing aapt: Cannot run program “/path/to/aapt”: error=2, No such file or directory: error=2, No such file or directory

Even though the ADT bundle provides a 64 bit version, the system requirements indicate that “64-bit distributions must be capable of running 32-bit applications.”  I failed to see that when installing it under Fedora Core 20 and was getting the following error from Eclipse:

Error executing aapt: Cannot run program "/home/rchapin/sdks/adt-bundle-linux-x86_64-20131030/sdk/build-tools/android-4.4/aapt": error=2, No such file or directory: error=2, No such file or directory  android_sdk    line 1   Android ADT Problem

I checked to see if the file was there.  Yep.  I checked to see if was executable.  Yep.

It was only after finding a blog post about it and doing a file command on it that I noticed that it was a 32 bit executable:

file adt-bundle-linux-x86_64-20131030/sdk/build-tools/android-4.4/aapt 
adt-bundle-linux-x86_64-20131030/sdk/build-tools/android-4.4/aapt: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, not stripped

All I had to do was install the 32 bit libraries that the binaries are linked against:

yum install glibc.i686 zlib.i686 libstdc++.i686 ncurses-libs.i686 libgcc.i686

Once installed, the error should disappear from Eclipse as it tries to invoke the binaries and do a regular build and/or restarting or cleaning the project should clear the errors.

Setting up Android in Eclipse, Unable to resolve target ‘android-18’

When setting up Eclipse for Android development, after you have installed the Develeper Tools and NDK Plugins and linked to the ADT-bundle and then imported your project (see othere posts related by searching for ‘android’) I got the following error:

[2014-03-24 14:14:53 - android_sdk] Unable to resolve target 'android-18'

I went and checked to make sure that the Platform.MinPlatformToolsRev property in the ~/path/to/adt-bundle-linux-x86_64-20131030/sdk/tools/source.properties matched that of my project.properties file.

They were both 18.  Eh?  Why the error?

So, in Eclipse, I went to the Window > Android SDK Manager and looked at the version of the Android SDK Platform that was installed.  It was:

Android 4.4.2 (API 19) and the checkbox next to SDK Platform under that sub-heading was checked.

So, I went back to my project.properties and updated the target property to:

target=android-19

which eliminated that error.