Bash: Sorting .jpg files into directories based on EXIF time

October 8th, 2013 by Leandro Morgado

I had a bunch of .jpg photos in one directory and wanted to place them into folders by date. Here is how I automated that:

shell> exiftool 20130823_210740.jpg | grep -i date
File Modification Date/Time     : 2013:08:23 21:07:40+01:00
Modify Date                     : 2013:08:23 21:07:40
Date/Time Original              : 2013:08:23 21:07:40
Create Date                     : 2013:08:23 21:07:40
 
shell> for i in $(ls -1 *.jpg); do VAR=$(exiftool $i | grep "Date/Time Original"| cut -d' ' -f16-17 | cut -d':' -f2-4| tr : _ ); echo mkdir -p $VAR; echo mv $i $VAR ; done
mkdir -p 2013_08_23
mv 20130823_210740.jpg 2013_08_23
mkdir -p 2013_08_23
mv 20130823_210744.jpg 2013_08_23
^C
 
shell> for i in $(ls -1 *.jpg); do VAR=$(exiftool $i | grep "Date/Time Original"| cut -d' ' -f16-17 | cut -d':' -f2-4| tr : _ ); mkdir -p $VAR; mv $i $VAR ; done
 
shell> ls
2013_08_23	2013_08_31	2013_09_06	2013_09_11	2013_09_15	2013_09_22	2013_10_05
2013_08_26	2013_09_01	2013_09_08	2013_09_12	2013_09_20	2013_09_26	2013_10_06
2013_08_30	2013_09_03	2013_09_09	2013_09_13	2013_09_21	2013_09_27

Bash: script to remove all spaces and uppercase chars from multiple filenames

January 17th, 2012 by Leandro Morgado

I needed to remove the spaces in filenames for many files but doing it by hand was a chore. Here is a small script that did the job for me:

#!/bin/bash
read -p "Are you sure you want to rename all files? (Y/N)" contflag
flag=$(echo $contflag| tr A-Z a-z)
if [ ! ${flag} == "y" ] ; then
 exit 1
fi
for f in *; do
     file=$(echo $f | tr A-Z a-z | tr ' ' _)
     [ ! -f $file ] && mv "$f" $file
done
exit 0

I know this could be improved, for example, by taking a list of files as an argument, but it does what I want. Use at your own risk.

Happy file renaming! =)

Lua and mysql-proxy: how to send a query to an email

March 11th, 2011 by Leandro Morgado

I recently got an inquiry on how to receive an email every time a query was executed via the MySQL proxy. This is very simple and you can achieve it by simply piping the query to the *nix mail command. Here is the sample code (in a file caled send_mail.lua):

1
2
3
4
5
6
7
function read_query(packet)
  if string.byte(packet) == proxy.COM_QUERY then
    print("Hello world! Seen the query: " .. string.sub(packet, 2))
    print("Sending query to email:")
    os.execute("echo " .. string.sub(packet, 2) .. "| mail -s'Lua test' your.email.here@example.com ")
  end
end

To execute this, install proxy as per the instructions in the manual. Then simply run the proxy and point it at your script:

shell> bin/mysql-proxy --proxy-lua-script=send_email.lua &

Finally, connect to the proxy and issue a query:

shell> mysql -h127.0.0.1 --port=4040
...
mysql> SELECT "Test 1";
Hello world! Seen the query: SELECT "Test 1"
Sending query to email:
+--------+
| Test 1 |
+--------+
| Test 1 |
+--------+
1 row in set (0.00 sec)

You’ll shorty receive email with the query above. Happy Lua scripting.

Configuring MySQL Enterprise Monitor to authenticate from LDAP

October 11th, 2010 by Leandro Morgado

In the last post, we saw how to create a test OpenLDAP server, populate it and secure it with SSL certificates. Now we are going to have a look at how to configure MySQL Enterprise Manager (MEM) to authenticate against LDAP. We will be examining a few different kinds of setup methods.

1. Using LDAP to fetch just the user password

The simplest form is to configure a user with MEM and set it to the LDAP type. The user’s role is setup in MEM during user creation time and is not fetched from LDAP. Below you can see the user definition page:

How to create a LDAP user in MEM - password only

How to create a LDAP user in MEM - password only

The username is user1 as specified in MEM, but where do we get the password from? We need to tell MEM how to find this user. Here is a sample user as defined by the LDIF file used in my previous post:

# user1, People, example.com
dn: uid=user1,ou=People,dc=example,dc=com
objectClass: person
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: top
cn: Aaren Atp
sn: Atp
description: This is the description for Aaren Atp.
employeeNumber: 1
givenName: Aaren
homePhone: +1 280 375 4325
initials: ALA
l: New Haven
mail: user.1@maildomain.net
mobile: +1 680 734 6300
ou: admin
pager: +1 850 883 8888
postalAddress: Aaren Atp$70110 Fourth Street$New Haven, OH  93694
postalCode: 936942
st: OH
street: 70110 Fourth Street
telephoneNumber: +1 390 103 6917
uid: user1
userPassword:: e1NTSEF9Z0tsZjU4cm50Wit4b045N0U4cWlldVJQK1RMOVAzTGw=

Now tell MEM to look for the uid by navigating to Settings > Global Settings > LDAP Authentication:

MEM settings for LDAP password lookup only

MEM settings for LDAP password lookup only

The password is specified in the userPassword attribute and uses standard LDAP supported formats. Technically what MEM does is an LDAP simple bind operation (Authentication Mode = Bind as User) with the given username/password and then attempts to search for the given user using the DN pattern.  If the binding and search succeeds, we assume the password is correct. With this in place, you can now login with user1 without having to specify the password in MEM.

2. Adding MEM Roles from LDAP

If we want to fetch the user’s role from LDAP in addition to the password, we need to enable the Map LDAP Roles to Application Roles check box in the LDAP settings page. We’ll see the two ways of doing this shortly.

The good thing about enabling role mapping is that manual user creation in the Web dashboard is no longer required. If the user does not already exist within MEM, it will be “copied” from LDAP to MEM when that user first logs in. The lookup order is Built-in users first, then LDAP users. If you want user authentication to be exclusively done against LDAP then make LDAP authoritative by ticking the check box:

MEM authoritative LDAP authentication

MEM authoritative LDAP authentication

WARNING: Enabling this prevents Built-in users from being authenticated. Make sure that you test with non authoritative authentication first and make sure role mapping is working. Also, ensure that you have a valid LDAP user who has admin privileges or risk locking yourself out.

Below is an example of how my test user table looked before logging in with user1:

User table before LDAP login

User table before LDAP login

And this is how it looks after a successful login:

User table after LDAP login

User table after LDAP login

Notice how the LDAP user1 entry was created automatically in the MEM user table with values from the LDAP directory.

2.2.1 MEM roles in a LDAP user’s attribute

The first way of achieving role mapping is to simply have an attribute in the user’s entry, whose attribute value will be the role. In our example, we use the ou attribute. The relevant attributes for our sample users are:

uid: user1
ou: admin
....
uid: user2
ou: dba

The relevant settings in MEM are:

MEM settings for LDAP role mapping with user attributes

MEM settings for LDAP role mapping with user attributes

Now when you login with user2 for example, its role will be fetched from LDAP. We can verify this in the User Preferences section as shown by the screenshot below:

A user that has authenticated via LDAP with role mapping

A user that has authenticated via LDAP with role mapping

If we try user1, then we will get an admin (manager) role.

Note that some versions have a bug that prevents this setup from working. Check if you are affected.

2.2.2 MEM roles specified by a LDAP group

There is another way to specify a user’s role. Instead of each user having an attribute representing the role, a roles group is created, which enumerates the users that are members of that role. In our example, this is represented in the LDIF file as:

dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: groups

dn: cn=admin,ou=groups,dc=example,dc=com
objectClass: groupOfUniqueNames
cn: admin
uniqueMember: uid=user1,ou=People,dc=example,dc=com

dn: cn=dba,ou=groups,dc=example,dc=com
objectClass: groupOfUniqueNames
cn: dba
uniqueMember: uid=user2,ou=People,dc=example,dc=com

So again, we need to tell MEM how to do role lookups from the LDAP directory.  This is how the LDAP settings in MEM would look like for our particular case:

MEM settings for LDAP role mapping in groups

MEM settings for LDAP role mapping in groups

Note, that due this bug, you might not get this particular setup to work.

2.3 Configuring LDAP lookups to use SSL and STARTTLS

Once plain text authentication is working, you can choose to secure communications between MEM and the LDAP server with either STARTTLS or SSL. Obviously the LDAP server must support it. Note that SSL (ldaps) is deprecated in the latest LDAP v3 and STARTTLS is prefered. MEM supports both types. To use STARTTLS, simply select it in the menu as follows:

MEM with STARTTLS LDAP authentication

MEM with STARTTLS LDAP authentication

There is no need to change the default port. Using SSL (ldaps) however, implies using the ldaps port, which by default is 636, and setting MEM to use SSL(ldaps) :

MEM with SSL (ldaps) LDAP authentication

MEM with SSL (ldaps) LDAP authentication

One thing to note is that the (Primary) Server Hostname should match the SSL certificate of the LDAP server.

If you are using self signed certificates that were not issued by a commercial SSL company, MEM will not have the root CA (Certificate Authority) in it’s repository. You should see a message in the $INSTALL_DIR/monitor/apache-tomcat/logs/catalina.out logfile:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

To fix this, you will need to import the your root CA certificate that was used to generate the LDAP server’s certificate. This can be achieve with the Java Keytool utility as follows:

shell> cd  /opt/mysql/enterprise/monitor/java
shell> bin/keytool -import -trustcacerts -alias ldapssl \
       -file /etc/openldap/ssl/ca-cert.pem -keystore lib/security/cacerts

This needs to be run under MEM’s Java installation directory. Unless you have previously modified it, the default password is changeit . We saw how to create a CA certificate (ca-cert.pem) in the previous post. Finally, restart the MEM monitor service.

In case you have problems importing your root CA certificate, make sure it is correctly format and acceptable by the Java keytool utility:

keytool can import X.509 v1, v2, and v3 certificates, and PKCS#7 formatted certificate chains consisting of certificates of that type. The data to be imported must be provided either in binary encoding format, or in printable encoding format (also known as Base64 encoding) as defined by the Internet RFC 1421 standard. In the latter case, the encoding must be bounded at the beginning by a string that starts with ‘—–BEGIN’, and bounded at the end by a string that starts with ‘—–END’.”

http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/technotes/tools/windows/keytool.html

To troubleshoot, the best place is to look at the catalina.out logfile. If you need extra debugging information, you can start MEM’s JVM as follows:

JAVA_OPTS="$JAVA_OPTS -Djavax.net.debug=ALL"

In the current version (2.2.1.1721) this should be added at around line 180 of $INSTALL_DIR/monitor/apache-tomcat/bin/catalina.sh. Note that catalina.sh will get overwritten when you next upgrade so if you want JAVA_OPTS changes to be persistent, then use setenv.sh (or setenv.bat for Windows.). A Tomcat restart is needed. Note that a lot of information is logged and you’re log files will grow rather quickly. Please remember to turn this off in regular production mode.

Hopefully this will help when configuring MEM to authenticate it’s users against a LDAP directory.

Setting up OpenLDAP for MySQL Enterprise Monitor

October 11th, 2010 by Leandro Morgado

The latest 2.2 release of MySQL Enterprise Monitor (MEM) has the ability to authenticate against LDAP. I decided to test this setup and for that, I had to create and populate an OpenLDAP server, including STARTTLS/SSL certificates. This guide was done on CentOS 5.5 but it shouldn’t be much different in other Linux/Unix distributions. First, start off by installing the packages with:

root@shell> yum install openldap openldap-clients openldap-servers

Then head to /etc/openldap where you can set you domain and the DN for the LDAP manager user. I’ve inserted some useful comments into the slapd.conf file. Lines without comments have not been changed from the default slapd.conf file.

shell> grep -v "^#" /etc/openldap/slapd.conf | grep -v "^$"
include		/etc/openldap/schema/core.schema
include		/etc/openldap/schema/cosine.schema
include		/etc/openldap/schema/inetorgperson.schema
include		/etc/openldap/schema/nis.schema
allow bind_v2
pidfile		/var/run/openldap/slapd.pid
argsfile	/var/run/openldap/slapd.args
#The lines below are for SSL and STARTTLS.
#I'll show you how to generate certs later on
TLSCipherSuite HIGH:MEDIUM:-SSLv2
TLSCACertificateFile /etc/openldap/ssl/ca-cert.pem
TLSCertificateFile /etc/openldap/ssl/server-cert.pem
TLSCertificateKeyFile /etc/openldap/ssl/server-key.pem
#This allows ldapsearch command to connect without a client cert
TLSVerifyClient never
database	bdb
# this is your domain. I used example.com for my tests.
suffix		"dc=example,dc=com"
# this is the "username" of the LDAP admin for this domain
rootdn		"cn=Manager,dc=example,dc=com"
# this is the encripted password. To generate a SSHA password use slappasswd.
rootpw {SSHA}8diJsdIYFRr/wt7vqk3SGj6b/ZZZ21eno
directory	/var/lib/ldap
index objectClass                       eq,pres
index ou,cn,mail,surname,givenname      eq,pres,sub
index uidNumber,gidNumber,loginShell    eq,pres
index uid,memberUid                     eq,pres,sub
index nisMapName,nisMapEntry            eq,pres,sub

If for some reason, you need to compile your own version of OpenLDAP, see this guide:
http://www.openldap.org/doc/admin24/quickstart.html

The next step is to generate our certificates. First we generate the Certificate Authority and the LDAP Server certificates. One important thing is to set the CN attribute to your server’s hostname in both certificates. You can run the hostname command in the shell to find that out. This is the same hostname you will be using in the MEM setup or to test with the ldapsearch command line utility.

# Create CA and Server Certs
shell> openssl genrsa 2048 > ca-key.pem
shell> openssl req -new -x509 -nodes -days 1000 -key ca-key.pem > ca-cert.pem
shell> openssl req -newkey rsa:2048 -days 1000 -nodes -keyout server-key.pem > server-req.pem
shell> openssl x509 -req -in server-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem

These files should be located under /etc/openldap/ssl and the server key needs to be chmoded:

shell> chmod 600 /etc/openldap/server-key.pem

Then we create the certificate for our client utilities, and let openldap know about it:

# Create client certificate
shell> openssl req -newkey rsa:2048 -days 1000 -nodes -keyout client-key.pem > client-req.pem
shell> openssl x509 -req -in client-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem
shell> cat /etc/openldap/ldap.conf
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
#BASE	dc=example, dc=com
#URI	ldap://ldap.example.com ldap://ldap-master.example.com:666
#SIZELIMIT	12
#TIMELIMIT	15
#DEREF		never
#TLS_CACERTDIR /etc/openldap/cacerts
TLS_CACERT /etc/openldap/ssl/ca-cert.pem

Here are how the permissions on these files look like for me:

shell> ls -la /etc/openldap/ssl/
total 40K
drwxr-xr-x 2 root root 4.0K Jun 23 13:53 .
drwxr-xr-x 5 root root 4.0K Jun 25 20:59 ..
-rw-r--r-- 1 root root 1.5K Jun 23 13:51 ca-cert.pem
-rw-r--r-- 1 root root 1.7K Jun 23 13:51 ca-key.pem
-rw-r--r-- 1 root root 1.2K Jun 23 13:53 client-cert.pem
-rw-r--r-- 1 root root 1.7K Jun 23 13:53 client-key.pem
-rw-r--r-- 1 root root 1.1K Jun 23 13:53 client-req.pem
-rw-r--r-- 1 root root 1.2K Jun 23 13:52 server-cert.pem
-rw------- 1 ldap root 1.7K Jun 23 13:52 server-key.pem
-rw-r--r-- 1 root root 1.1K Jun 23 13:52 server-req.pem

Next enable SSL for OpenLDAP and start up the server:

shell> grep -v "^#" /etc/sysconfig/ldap | grep -v "^$"
ULIMIT_SETTINGS=
STOP_DELAY=3s
SLAPD_LDAP=yes
SLAPD_LDAPS=yes
SLAPD_LDAPI=no
shell> /etc/init.d/ldap start
Checking configuration files for slapd:  bdb_db_open: Warning - No DB_CONFIG file found in directory /var/lib/ldap: (2)
Expect poor performance for suffix dc=example,dc=com.
config file testing succeeded                                                           [  OK  ]
Starting slapd:                                            [  OK  ]
shell> ps aux | grep slapd
ldap     25224  0.0  2.3 392036 191288 ?       Ssl  21:01   0:00 /usr/sbin/slapd -h ldap:/// ldaps:/// -u ldap

Don’t worry about the warning. Let’s try and query the LDAP directory now:

shell> ldapsearch -x -h localhost -b 'dc=example,dc=com'
# extended LDIF
#
# LDAPv3
# base  with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# search result
search: 2
result: 32 No such object
# numResponses: 1

As we can see, there are no entries yet. So let’s populate the directory with this LDIF file. You will be prompted for your password. It’s the one used to setup /etc/openldap/slapd.conf.

shell> ldapadd -x -D "cn=Manager,dc=example,dc=com" -W -f mem-ldap.ldif.txt
Enter LDAP Password:
adding new entry "dc=example,dc=com"
adding new entry "ou=People,dc=example,dc=com"
adding new entry "uid=user1,ou=People,dc=example,dc=com"
adding new entry "uid=user2,ou=People,dc=example,dc=com"
adding new entry "ou=groups,dc=example,dc=com"
adding new entry "cn=admin,ou=groups,dc=example,dc=com"
adding new entry "cn=dba,ou=groups,dc=example,dc=com"

And now we can see the results with:

shell> ldapsearch -x -H ldap:///localhost -b 'dc=example,dc=com'
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# example.com
dn: dc=example,dc=com
objectClass: domain
objectClass: top
dc: example
# People, example.com
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: People
# user1, People, example.com
dn: uid=user1,ou=People,dc=example,dc=com
objectClass: person
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: top
cn: Aaren Atp
sn: Atp
description: This is the description for Aaren Atp.
employeeNumber: 1
givenName: Aaren
homePhone: +1 280 375 4325
initials: ALA
l: New Haven
mail: user.1@maildomain.net
mobile: +1 680 734 6300
ou: admin
pager: +1 850 883 8888
postalAddress: Aaren Atp$70110 Fourth Street$New Haven, OH  93694
postalCode: 936942
st: OH
street: 70110 Fourth Street
telephoneNumber: +1 390 103 6917
uid: user1
userPassword:: e1NTSEF9Z0tsZjU4cm50Wit4b045N0U4cWlldVJQK1RMOVAzTGw=
# user2, People, example.com
dn: uid=user2,ou=People,dc=example,dc=com
objectClass: person
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: top
cn: Aaren Atp
sn: Atp
description: This is the description for Aaren Atp.
employeeNumber: 2
givenName: Aaren
homePhone: +1 280 375 4325
initials: ALA
l: New Haven
mail: user2@maildomain.net
mobile: +1 680 734 6300
ou: dba
pager: +1 850 883 8888
postalAddress: Aaren Atp$70110 Fourth Street$New Haven, OH  93694
postalCode: 936941
st: OH
street: 70110 Fourth Street
telephoneNumber: +1 390 103 6917
uid: user2
userPassword:: e1NTSEF9Z0tsZjU4cm50Wit4b045N0U4cWlldVJQK1RMOVAzTGw=
# groups, example.com
dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: groups
# admin, groups, example.com
dn: cn=admin,ou=groups,dc=example,dc=com
objectClass: groupOfUniqueNames
cn: admin
uniqueMember: uid=user1,ou=People,dc=example,dc=com
# dba, groups, example.com
dn: cn=dba,ou=groups,dc=example,dc=com
objectClass: groupOfUniqueNames
cn: dba
uniqueMember: uid=user2,ou=People,dc=example,dc=com
# search result
search: 2
result: 0 Success
# numResponses: 8
# numEntries: 7

You should also test encrypted connections, first with STARTTLS, by adding the -ZZ option:

shell> ldapsearch -x -h localhost -ZZ -b 'dc=example,dc=com'

You can also do it with SSL (ldaps), but this has been deprecated in LDAPv3:

shell> ldapsearch -x -H ldaps:///localhost -b 'dc=example,dc=com'

If you need to look at the OpenLDAP log files, you should enable them in syslog.conf:

# Log LDAP stuff
local4.*                        /var/log/ldap.log

By default, OpenLDAP writes to the LOG_LOCAL 4 facility. You should also set the loglevel to the amount of detail needed. Either check man slapd.conf or the documentation for the available levels.

At the moment, we have a running openldap server which is populated with two test users, ready to be used by MEM. In the next post, I will discuss how to setup MEM to authenticate against our LDAP server. If you need to manipulate your LDAP directory and need a graphical tool, I found Apache Directory Studio to be very nice.

Connecting JBDC to MySQL Enterprise Monitor’s Query Analyzer

October 11th, 2010 by Leandro Morgado

With the release of MySQL Enterprise Monitor (MEM) 2.2, there is now the ability to monitor queries using the Query Analyzer (QUAN) without needing the agent proxy to be running. You can use a .NET or JDBC connector plugin to directly gather the query statistics. In the example below, we will use the MySQL Enterprise Plugin for Connector/J.

First, make sure both the Connector/J, the Connector/J plugin and the Apache Commons Logging jars are in the $CLASSPATH. At the time of writing, these are the files needed:

mysql-connector-java-5.1.12-bin.jar
c-java-mysql-enterprise-plugin-1.0.0.42.jar
required/commons-logging-1.1.1.jar

Then, add the plugin to the connection string so that it changes from something like this:

conn =	DriverManager.getConnection("jdbc:mysql://localhost:3306/test?"+"user=root&password=PASSWORD");

to something like this:

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?"
       +"user=root&password=PASSWORD"
       +"&statementInterceptors=com.mysql.etools.jdbc.StatementPerformanceCounters"
       +"&serviceManagerUrl=http://memserverhost.com:18080/"
       +"&serviceManagerUser=agent&serviceManagerPassword=AGENTPASSWORD");

Here is the full example code:

import java.sql.*;
 
// Notice, do not import com.mysql.jdbc.*
// or you will have problems!
 
public class LoadDriver {
    public static void main(String[] args) {
 
        try {
            // The newInstance() call is a work around for some
            // broken Java implementations
 
           	Class.forName("com.mysql.jdbc.Driver").newInstance();
 
	        Connection conn = null;
		conn =	DriverManager.getConnection("jdbc:mysql://127.0.0.1:33306/test?"+"user=root&password=PASSWORD"+"&statementInterceptors=com.mysql.etools.jdbc.StatementPerformanceCounters&serviceManagerUrl=http://memserverhostname.com:18080/&serviceManagerUser=agent&serviceManagerPassword=AGENTPASSWORD");
 
		//Get a Statement object
	      	Statement stmt = conn.createStatement();
    		ResultSet rs = stmt.executeQuery("SELECT SLEEP(10)");
		System.out.println("Closing connection");
		rs.close();
		conn.close();
        } catch (Exception ex) {
            // handle the error
	    ex.printStackTrace();
        }
    }
}

Now, when you Java application runs queries, they will be analyzed by QUAN. In my example code, there is a sleep call for 10 seconds. You can clearly see that this query was caught by QUAN:

Slow queries fed to QUAN using the Connector/J plugin

This now eliminates the need for the monitoring agent to be running it’s own instance of mysql-proxy for QUAN. Java and .NET applications can simply use the interceptor, saving on resources.

Of course, prior to setting this up, you should always check the online documentation.

Bash history format

January 16th, 2010 by Leandro Morgado

Sometimes I need to find out when a certain command was executed in the bash shell. By default, the bash shell will give you this:

shell> history | tail -n 2
 1004  history
 1005  history | tail -n 2

This won’t tell you the date but rather just the order that they were run in. If you want to temporarily see the date, then you need to set this:

shell> export HISTTIMEFORMAT='%F %T '
shell> history | tail -n 2
 1006  2010-01-16 00:55:47  export HISTTIMEFORMAT='%F %T '
 1007  2010-01-16 00:55:49 history | tail -n 2

This will last as long as your environment variable is set, so if you log out you will need to set it again. The %F and %T are standard strftime strings. Check the man page for the full range of options. If you want to make this setting permanent system wide, they add it to your /etc/profile .

Illusions

January 1st, 2010 by Leandro Morgado

Mum sent me some pics the other day. I found them pretty cool and trippy so I figured I’d share them. A couple of them are animated GIFs so make sure you click on them (twice) to view them properly.

sudo -i vs sudo -s

December 28th, 2009 by Leandro Morgado

A long time ago, every time I needed to do some admin work on Linux I used to “su -” into a root shell. After moving from Debian to Ubuntu, I noticed that “su -” would not work as the root account was disabled. So I started fooling the system with:

shell> sudo su -

But that was more a hack than anything else. You don’t actually need to run su with sudo to get a root shell. You can either sudo right away with:

shell> sudo -i
shell> sudo -s

So what are the differences between these? Well, the -i switch gives you the root shell environment, working the same way as “su -“. The -s switch preserves your own environment, and is equivalent to just running “su” with the dash.

Obviously, I’m not the only one who has come across this question and Ubuntu docs have a full page on this.

Happy rooting! :)

Gafes do Jornal Público

December 3rd, 2009 by Leandro Morgado

Costumo ler o feed RSS do Público e ultimamente tenho reparado numa quantidade enorme de erros, tanto ortográficos como gramaticais. Toda a gente comete o erro ocasional mas uma vez que se trata de um jornal, onde supostamente trabalham jornalistas profissionais, existe uma alta visibilidade para tais situações. Será que é pelas notícias serem publicadas na Web? Nunca vi semelhante coisa na imprensa escrita!

No espaço que se segue irei coleccionar tais gafes. Talvez sirva de incentivo para o grande chefe (da paz) do jornal comprar “spell checkers” para os funcionários.

Mettalica ou Metallica

Mettalica ou Metallica

 

 

Oops, as notas do editor ficaram no artigo!

Oops, as notas do editor ficaram no artigo!

Há uns tempos havia um artigo sobre os “cabeçilhas” de um grupo violento, mas ainda bem que já foi corrigido. No entanto, não deixa de ser engraçado ler os comentários.

Hoje apanhei um susto quando li que o tal soldado estava “asustado“! Até pensei que fosse um novo Netbook, Asus Tado:

asustado vs assustado

asustado vs assustado

Pelos vistos a IBM anda a fazer uma boas promoções, leve 2 pague 1:

IBM 2 por 1

IBM 2 por 1

E também fiquei a saber que o Newcastle mandou construir o seu estádio novo no St James Park de Londres. Pelos vistos a Rainha queria ver os jogos da varanda do Palácio de Buckingham! :)

Olhá lá, o St James Park fica aonde? Qual deles?

Olhá lá, o St James Park fica aonde? Qual deles?

Hoje fiquei a saber que o Público já consegue viajar no tempo e que daqui a 6 meses atrás vamos ter (ou será que já tivemos?) novas estações de Metro em Lisboa! Nota: Estamos em Agosto de 2009!

Back To The Future

Back To The Future

Durante a leitura de hoje sobre o caso Isaltino, descobri que afinal o homem é um intelectual de capacidade superior, tendo concluído a Licenciatura logo depois de “vir ao mundo”. Quem diria que o Isaltino foi um menino prodígio?!

Menino prodígio Isaltino

Hoje “aprendi” que o povo de Nigér não é nigerino nem nigerense mas antes nigeriano! Isto deixa os meus amigos da Nigéria em alguns apuros pois vão ter que arranjar outro gentílico!

 

nigerino vs nigeriano

nigerino vs nigeriano

Neste caso, o jornalista do Público decide rebaptizar o famoso jornal de negócios, Financial Times:

Financial vs Finantial

Financial vs Finantial

Hoje estava a ler sobre os fantásticos contributos do Sr. Alan Turing para decifrar o Enigma, quando descobri que afinal já não é crime ser homosexual no Reino Unido e o Sr. Turing foi perdoado. Até aprendi que tal processo chama-se “descriminação sexual” :

Alan Turing alvo de "descriminação"

Alan Turing alvo de "descriminação"

E agora um tema que me interessa bastante pessoalmente, as LAN Party (ai que saudades da Minho Campus Party!). Em Oeiras está a decorrer a XLParty que descobri ter “switchers da Holanda” (será que os Made in Taiwan não servem?) e um novo e emocionante jogo, o Conter Strike:

 

XLParty com "switchers da Holanda"

XLParty com "switchers da Holanda"

Será que posso utilizar o bing para procurar um corrector ortográfico em tempo real? Hint Hint!!

BNIG?

BNIG?

E um caso que está nos ouvidos do mundo é o da (do ?) atleta Semenya. Além de lhe retiram a medalha de ouro, agora metem-na dentro de um estádio qualquer e abandonam a rapariga lá dentro! Ora, isso não se faz! Sr Jornalista (ou tradutor “wannabe”), penso que artigo original diria algo como “abandoned in all stages”. É bom reparar que “stages” não significa estágios (curriculares ou profissionais?) nem muito menos estádios. Quanto muito seria abandonada em todos os palcos ou cenas, mas neste contexto penso que queriam dizer “abandonada em todas AS FASES do problema”! É uma coisa temporal e tal certo?

E o coitado do editor do jornal é que se tem de lembrar sempre dos outros, sem ninguém lhe retribuir o favor! Será que não houve uma alma caridosa que deixasse uma nota ao editor, a lhe lembrar para apagar as notas de edição?

Nota ao editor: tirar a nota do editor

Nota ao editor: tirar a nota do editor

Preparem-se que para o ano vai estar calor… hot.. hot…hot!

Que calor!

Que calor!

Ultimamente tenho visto muita porcaria no Público. Tanta que nem me tenho esforçado em a denúnciar. Mas depois de ler tanta coisa absurda e descuidada relativamente a valores monetários, não pude resistir. Em primeiro lugar, vim a saber que as coisa “Made in China” são realmente super “balatas”! Um linha de comboio de alta velocidade custa apenas 23 milhões de euros:

TGV "Made in China" = pechincha

TGV "Made in China" = pechincha

Ora, uma vez que o nosso querido Governo Português decidiu vender as nossa empresas públicas pela módica quantia de 6 mil milhões de euros, está visto que não teremos mais problemas em construir o TGV de Portugal. Aliás, com tanto dinheiro, aposto que o TGV vai chegar a todo o país, desde Pitões da Júnias à Ribeira Brava!

Governo estuda privatizar TAP, CTT, EDP, Galp, REN e seguradoras da CGD

Hoje, ao ler sobre uma empresa tecnológica portuguesa, vim a descobrir que só em receitas, este tem 9 mil milhões de euros!! Sim, ouviram bem, a Vision Box factura tanto, tanto, que num ano dava para pagar 390 linhas TGV Pequim-Xangai ou em alternativa, 150% do total de receitas das privatizações do governo!

Vision-Box com receitas de 9 mil milhões de euros anuais

Vision-Box com receitas de 9 mil milhões de euros anuais

Estou espantado como é que uma pequena empresa tem tanta capacidade! Para dar mais um exemplo, a minha entidade patronal, a SUN Microsystems (com 20-30 mil trabalhadores), foi recentemente adquirida pela Oracle pela módica quantia de ~7 mil milhões de US Dollars. Que pena que a Vision Box não se tenha chegada à frente! ;)

Bem, por enquanto é tudo. Vou actualizando esta página sempre que me deparar com tais “pérolas”.

Afinal, fartei-me de andar a corrigir os erros do Público e raramente actualizo esta notícia. Primeiro porque tenho tido mesmo tempo e segundo porque erros no Público, são todos os dias! Mas hoje vi um notícia com tantos erros que não pude resistir. Primeiro fiquei na dúvida quanto à nacionalidade tenista em questão:

Tem todos os olhos em bico não é?

Afinal, têm todos os olhos em bico não é?

Como não basta dar pontapés na Geografia, a Matemática e pontuação também sofrem as consequências desta “crise mundial”.

Super Avozinha com 54 anos ganha a jogar ténis

Super Avozinha com 54 anos ganha a jogar ténis

E com esta “pérola” fecho mais uma vez este artigo. Até uma próxima vez que veja tantos erros juntos.

 

Bem, já faz algum tempo que não actualizo isto. Tenho reparado que o Público confunde sistematicamente milhões (de euros, dólares) com mil milhões, e escreve coisas ridículas como “o Google e o Facebook estariam interessados em comprar a rede de microblogging, pela qual poderiam pagar cerca de dez milhões”. Isto quando na mesma notícia diz que o Twitter foi avaliado “em 3700 milhões de dólares”.

Grande pechinca para o Google e o Facebook não acham? Não bastando o brutal desconto no preço do Twitter, o público decidiu inflacionar o preço de certos domínios para 7500 a 9500 milhões de dólares. Continuando nesta lógica irracional, afirmam que o sex.com foi o domínio mais caro de sempre vendido por 13 milhões de dólares. A única explicação que encontro para estas contas é que os 7500 milhões não eram dólares Americanos mas sim, dólares do Zimbabwe!

Ficamos a saber que o tipo que vendeu o sex.com ganhou 13 milhões pelo seu domínio.

Mas espertos, espertos, foram os gajos do porn.com:

Estes tipos não só conseguiram cerca de 700 vezes o que foi pago pelo sex.com, mas também cerca de 950 vezes o valor to Twitter! ;)

 

cabecilhas de grupo violentco

« Previous Entries