Customize your Vim editor using .vimrc

Quick notes:
– imap is for when you are in insert mode
– map is when your are in command mode

Thus when you are in the insert mode, sometime you need to exit to the command mode first using the esc key.
The i is for going back to the inser mode. The cr key is the Enter key.

The script below will make vim to:
– Find and Replace when I hit F3
– Undo when I hit F9
– Saves when I hit F10
– Quit when I hit F12
– Prints a debugging statement for PHP when I press F8
– Also disables the REPLACE mode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
""""""""""""""""""""""""""""""""""""""
" Quick commands using F keys
"
""""""""""""""""""""""""""""""""""""""
:imap <F3> <esc>:%s/search/replace/gc
:map <F3> :%s/search/replace/gc

:imap <F9> <esc>:u<cr>i
:map <F9> :u<cr>i

:imap <F10> <esc>:w!<cr>i
:map <F10> :w!<cr>i

:imap <F12> <esc>:q!<cr>
:map <F12> :q!<cr>

:imap <F8> error_log("\n".__FILE__ . ' ['. __LINE__. '] ' . __CLASS__.'::'.__FUNCTION__.'() D>'. print_r(, true));<cr>
:map <F8> ierror_log("\n".__FILE__ . ' ['. __LINE__. '] ' . __CLASS__.'::'.__FUNCTION__.'() D>'. print_r(, true));<cr>

"""""""""""""""""""""""""""""""""""""""
"
Disable REPLACE mode
"""""""""""""""""""""""""""""""""""""""
function s:ForbidReplace()
    if v:insertmode isnot# 'i'
        call feedkeys("
\<Insert>", "n")
    endif
endfunction
augroup ForbidReplaceMode
    autocmd!
    autocmd InsertEnter  * call s:ForbidReplace()
    autocmd InsertChange * call s:ForbidReplace()
augroup END
Posted in Linux | Comments Off on Customize your Vim editor using .vimrc

Search and replace withing a file

1
2
3
4
5
6
7
sed -i -e"s/SEARCH_TEXT/REPPLACE_TEXT/g" FILENAME.txt

# another example using bakup
sed -i.bak -e"s/SEARCH_TEXT/REPPLACE_TEXT/g" FILENAME.txt

# another example using variable
sed -i -e"s/\/pathname/\/pathname-$date/g" "filename-"$date".xml"
Posted in Bash, Linux, Operating System | Comments Off on Search and replace withing a file

Bash Scripting Basics (Variable Assignment, If, Loop)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
##################################################
# Benchmark the processing time when wkhtmltopdf
# converts an html file to a pdf file
##################################################

if [[ $1 = "" || $2 = "" || $3 = "" ]]; then
        echo "Usage: `basename $0` sourceFile.html destinationFile.pdf iteartionRunTime"
else
        _min=9999
        _max=0
        _total=0
        _iteration=$3
        for (( _i=1; _i<=$_iteration; _i++ ))
        do
                _start_time=`date +%s`
                echo "running $_i"
                ~MYUSER/bin/benchmarkWkhtmltopdf.sh $1 $2  > /dev/null 2>&1
                _end_time=`date +%s`
                _processing_time=$((_end_time-_start_time))
                if [ "$_processing_time" -lt "$_min" ]; then
                        _min=$_processing_time
                fi
                if [ "$_processing_time" -gt "$_max" ]; then
                        _max=$_processing_time
                fi
                _total=$(($_total+$_processing_time))
        done
       _processing_time_average=$(echo - | awk "{print $_total/$_iteration}")
        echo "Processing time avg: $_processing_time_average  min:$_min  max:$_max total:$_total"
fi
Posted in Bash, Linux | Comments Off on Bash Scripting Basics (Variable Assignment, If, Loop)

Compress and Extract Files in Linux

Extract:

.tar.bz2
To extract a tar (Tape ARchiver) file, type the following in the shell prompt:

1
tar xvjf yourFileName.tar.bz2

Which will untar it to the current directory. Depending on the file structure that being compressed, it might create sub-directories.
Parameters:
x – extract
v – verbose output (lists all files as they are extracted)
j – deal with bzipped file
f – read from a file, rather than a tape device

.tar.gz or .tgz

1
2
tar xvzf file.tar.gz
tar xvzf file.tgz

Parameters:
-x, –extract, –get extract files from an archive
-v, –verbose verbosely list files processed
-z, –gzip, –gunzip, –ungzip filter the archive through gzip
-f, –file=ARCHIVE use archive file or device ARCHIVE

.bz2 file

1
tar jxf YOUR_FILE_NAME.bz2

.zip file

1
unzip YOUR_FILE_NAME.zip
Posted in Bash, Linux | Tagged | Comments Off on Compress and Extract Files in Linux

Using VBA macro for Excel

Let’s start with something simple. Assume that we have a big spreadsheet and we want to highlight it based on a certain subject — for example, expenses about car. For the sake of the example we’ll keep it short, but in real life you could be dealing with hundreds of rows.

Excel challenge 1

We can see that cell B2 and B7 contain the word “car”, so how do you highlight these cells? You can do this with a VBA macro — VBA gives you full programmatic control of Excel and is far more flexible than a single cell formula.

So let’s start programming!

1. Enable the VBA development environment. In Excel, press Alt + F11. If that doesn’t work:

  • Go to File > Options > Customize Ribbon
  • In the main tabs panel, check Developer
  • Click the Visual Basic icon
  • A new window will open titled “Microsoft Visual Basic for Applications”

Double-click Sheet 1, then go to Insert > Procedure at the top menu. Give it a meaningful name like HighlightCarExpenses.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Public Sub HighlightCarExpenses()
    Rem this is a comment
    Dim emptyCounter As Integer, currentRow As Integer
    Dim currentCell As Range
    Dim currentCellValue As String

    Rem Set initial value for the empty cell counter
    emptyCounter = 0
    currentRow = 1
    currentCellValue = ""

    Rem Scan all column B values
    Rem Stop scanning if we see 3 empty cells in column B in a row
    Do While (emptyCounter < 3)
        currentCellValue = ActiveSheet.Cells(currentRow, 2).Value
        Debug.Print "Value at row " & currentRow & ": " & currentCellValue

        If (currentCellValue = "") Then
            emptyCounter = emptyCounter + 1
        ElseIf InStr(1, currentCellValue, "car", 1) Then
            Debug.Print "Car is found at row: " & currentRow
            ActiveSheet.Cells(currentRow, 2).Interior.Color = RGB(255, 0, 0)
        End If
        currentRow = currentRow + 1
    Loop
    Debug.Print "last row " & currentRow
End Sub

The macro walks down column B and stops once it sees three empty cells in a row — a simple way to guess where the data ends without hard-coding a row count. InStr(1, currentCellValue, “car”, 1) does a case-insensitive substring search (the trailing 1 is the vbTextCompare flag), so “Car”, “CAR”, and “old car” all match.


A few things worth knowing.

RGB values go 0–255, not 0–256. The original macro had RGB(256, 0, 0) which is technically out of range — different Excel versions handle the overflow differently (some clamp to 255, some wrap, some raise an error). The version above uses RGB(255, 0, 0), which is the actual “pure red”. Easy mistake to make if you’re used to 0-indexed integers; VBA’s RGB isn’t.

Dim a, b As Integer doesn’t do what you’d expect. Coming from C, Java, or JavaScript, you’d assume Dim emptyCounter, currentRow As Integer declares both as Integer. It doesn’t — VBA only types the last variable on the line; emptyCounter ends up as Variant. The fix is to type each variable explicitly, as in the macro above: Dim emptyCounter As Integer, currentRow As Integer. This is genuinely one of VBA’s most copy-pasted bugs.

Conditional Formatting can do this without VBA. The original post said you couldn’t highlight “contains car” with a formula — that’s not quite true. Excel’s built-in Conditional Formatting has had a “Format only cells that contain → Specific Text → containing → car” rule for years, and it’ll do exactly what this macro does without writing any code. Reach for VBA when you need behaviour that Conditional Formatting can’t express — multi-step logic, data manipulation, talking to other workbooks — not for simple highlight-by-text.

VBA still works, but Office Scripts is the modern alternative. VBA is great on Windows desktop Excel and isn’t going anywhere, but if you’re on Excel for Mac or Excel on the web, look at Office Scripts — TypeScript-based, runs in Microsoft 365, and it’s the path Microsoft is investing in for cross-platform automation. Same kind of “loop down a column and tweak cells” model, just with modern syntax. 💡

Glossary

Comment: A part of the code (sentences) that will not be executed by the system. A way for the programmer to leave a note. In VBA, comments start with an apostrophe () or the keyword Rem.

Debug: Trace value(s) to find and remove mistakes, or just to ensure program correctness. Debug.Print writes to the Immediate Window in the VBE (open it with Ctrl + G).

Dim: A declaration for a variable.

Sub: A procedure that runs but does not return a value. Public Sub means it can be called from other modules and shows up in the Macros dialog.

Range: A reference to one or more cells (e.g. a single cell, a row, a column, or a rectangular block). The base type for almost everything you do in Excel programmatically.

Integer: A whole-number data type. Examples: 1, 2, 3.

String: An alpha-numeric data type. Examples: “I have 2 dogs”, “Expenses are bad”. Strings are always written in double quotes.

Posted in Visual Basic | Comments Off on Using VBA macro for Excel

Remote copy using scp

Do you ever need to copy one file from one server to another? If you have ssh access to the remote server then you can do an scp command like so:

1
$ scp remoteUsername@remoteServername:remoteFile localFile
Posted in Linux, Operating System | Tagged | Comments Off on Remote copy using scp

Delete files older than X number of days in Linux

Say you backup your database daily and you need to delete the old backup files.
You can issue the command bellow which will erase any files within the specified directory that are older than 7 days.

1
$ find /your/target/directory* -mtime +7 -exec rm {} \;
Posted in Bash, Linux, Operating System | Comments Off on Delete files older than X number of days in Linux

LDAP basics: Base DN, Search Filters, and a test directory in 5 minutes

If you’ve ever pasted an LDAP query into a config file without really understanding what each piece means, this post is for you. We’ll cover the two concepts that trip people up most — Base DN and Search Filter — then spin up a real LDAP server in Docker and run a few queries against it. By the end you’ll be able to read (and write) most LDAP queries you encounter in the wild. 🗂️

The mental model

An LDAP directory is a tree. Every entry has a unique Distinguished Name (DN) — its full path from the root, written right-to-left, comma-separated. For example:

1
uid=alice,ou=people,dc=example,dc=org

This says: an entry with uid=alice, inside the people Organisational Unit, inside the example.org domain. Each piece is a Relative Distinguished Name (RDN); the whole chain is the DN. Common pieces:

  • dc = domain component (for example.org: dc=example,dc=org)
  • ou = organisational unit (a folder, basically — ou=people, ou=groups)
  • cn = common name (a person’s name, a group name)
  • uid = user identifier (login name, on most Unix-style directories)

Base DN — “where to start looking”

The Base DN is the node in the tree where your search starts. Think of it as cd-ing into a directory before running find. Pick it well and you skip work; pick it badly and you scan the whole tree (or worse, you miss what you wanted).

  • dc=example,dc=org — search the entire directory
  • ou=people,dc=example,dc=org — only search inside the people branch
  • uid=alice,ou=people,dc=example,dc=org — start at exactly one entry (useful with scope=base; see below)

Combined with the Base DN, the scope tells the server how deep to go: base (just that one node), one (immediate children only), or sub (the whole subtree). sub is the default in most clients.

Search Filter — “which entries to return”

Search Filters are RFC 4515 expressions wrapped in parentheses. The basic shape is (attribute=value). Some examples:

  • (uid=alice) — exact match
  • (cn=A*) — common name starts with “A”
  • (objectClass=person) — every entry of class person
  • (mail=*) — has any value for mail (i.e. attribute is present)

Combine filters with the prefix-notation operators & (AND), | (OR), ! (NOT). The operator goes first, then the sub-filters, all wrapped in their own parens:

  • (&(objectClass=person)(uid=alice)) — person AND uid=alice
  • (|(uid=alice)(uid=bob)) — uid=alice OR uid=bob
  • (&(objectClass=person)(!(uid=admin))) — every person except admin

It looks alien at first because of the prefix notation, but it’s actually consistent — once you spot that the operator always comes before its operands, the rest is just nesting.

A test directory in 5 minutes (Docker)

Reading about LDAP is a slog. Running queries against a real directory is faster. The osixia/openldap image ships an OpenLDAP server with sensible defaults and a one-line spin-up:

1
docker run -p 389:389 -p 636:636 --name my-openldap --detach osixia/openldap:1.5.0

That’s it. The container boots with these defaults:

  • Organisation: Example Inc.
  • Domain: example.orgBase DN: dc=example,dc=org
  • Admin DN: cn=admin,dc=example,dc=org, password: admin
  • Port 389 (LDAP) and 636 (LDAPS) on the host

A quick note on the image: osixia/openldap is largely unmaintained as of 2021 — last tagged release is 1.5.0 — but it’s still excellent for a five-minute tutorial because it does the right thing out of the box. For long-running production use, look at bitnami/openldap or run OpenLDAP directly on a host you control.

Now load a few sample entries. Save the following as seed.ldif:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
dn: ou=people,dc=example,dc=org
objectClass: organizationalUnit
ou: people

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

dn: uid=alice,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
cn: Alice Anderson
sn: Anderson
uid: alice
mail: alice@example.org
userPassword: alicepass

dn: uid=bob,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
cn: Bob Brown
sn: Brown
uid: bob
mail: bob@example.org
userPassword: bobpass

dn: uid=carol,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
cn: Carol Carter
sn: Carter
uid: carol
mail: carol@example.org
userPassword: carolpass

Then load it with ldapadd (install ldap-utils on Debian/Ubuntu, openldap-clients on RHEL, or brew install openldap on macOS):

1
ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=org" -w admin -f seed.ldif

The flags: -x simple bind (no SASL), -H the server URL, -D the bind DN, -w the password, -f the LDIF file.

Now run some queries

List everyone in the directory:

1
ldapsearch -x -H ldap://localhost -b "dc=example,dc=org" "(objectClass=person)"

The -b flag is the Base DN; the quoted (objectClass=person) is the Search Filter. Notice we didn’t bind as anyone — anonymous bind is allowed by default for read.

Just the people branch, with a narrower base DN:

1
2
3
ldapsearch -x -H ldap://localhost \
  -b "ou=people,dc=example,dc=org" \
  "(objectClass=inetOrgPerson)"

Find one user, returning only their email and full name:

1
2
3
ldapsearch -x -H ldap://localhost \
  -b "dc=example,dc=org" \
  "(uid=alice)" cn mail

The trailing cn mail is the attribute list — without it, the server returns every attribute on the entry. Always specify the attributes you actually need; it’s faster and easier to read.

Wildcard prefix match — everyone whose cn starts with “A” or “B”:

1
2
3
ldapsearch -x -H ldap://localhost \
  -b "ou=people,dc=example,dc=org" \
  "(|(cn=A*)(cn=B*))" cn

Combined AND filter — every person who has a mail attribute and isn’t admin:

1
2
3
ldapsearch -x -H ldap://localhost \
  -b "dc=example,dc=org" \
  "(&(objectClass=person)(mail=*)(!(cn=admin)))" cn mail

Active Directory and dsquery

Microsoft Active Directory speaks LDAP, but adds its own conventions. The dsquery command is the Windows-side equivalent of ldapsearch:

1
dsquery * "CN=Users,DC=myadserver,DC=com" -scope onelevel -attr objectguid proxyaddresses -limit 2000 >C:\myadserver.user.list.txt

Unpack that the same way: “CN=Users,DC=myadserver,DC=com” is the Base DN, -scope onelevel is the scope (immediate children only), -attr objectguid proxyaddresses is the attribute list. There’s no explicit filter, so * means “all entries” — equivalent to (objectClass=*).

A few AD-specific gotchas worth knowing:

  • AD typically stores users under CN=Users, not OU=People — and CN=Users is a built-in Container, not an Organisational Unit, so you can’t apply Group Policy to it. Real environments usually move users into custom OUs.
  • Use sAMAccountName for the pre-Windows 2000 logon name (the most common login attribute), and userPrincipalName for the email-style login (alice@corp.example.com).
  • Filter for users (and exclude computer accounts) with (&(objectCategory=person)(objectClass=user)) — using objectClass=user alone also matches computer objects.
  • To find disabled accounts, you bit-test userAccountControl: (userAccountControl:1.2.840.113556.1.4.803:=2). That’s the LDAP_MATCHING_RULE_BIT_AND OID — yes, really, it’s that ugly. Welcome to AD.

Tools worth knowing

  • ldapsearch / ldapadd / ldapmodify — the standard CLI tools, on the command line of every Linux box once you install ldap-utils
  • Apache Directory Studio — free GUI, good for browsing the tree and visually composing filters
  • JXplorer — older but still works, lighter than Directory Studio
  • Windows: dsquery, Active Directory Users and Computers, ldp.exe — the built-in trio for AD

Once Base DN, Search Filter, and scope click, every LDAP query you’ll see in the wild — from a Jenkins auth config, a SSSD setup, a Keycloak federation, an old Java InitialDirContext — is just those three concepts plus a credential. Have fun. 🌳

Posted in LDAP and Active Directory | Comments Off on LDAP basics: Base DN, Search Filters, and a test directory in 5 minutes

Calling a mysql query from linux or dos command line

There are times when you want to call a mysql command from the bash or dos script then call this script in a scheduler (cron job).
The example below will show you how to do so.

1
mysql -uYOURUSERNAME -pYOURPASSWORD -DYOURDATABASE -e"CALL YOURSTOREDPROCEDURE('YOUR_SP_PARAMETER')"

Explanation:
-u is where you put your username, you can either put a space or no space at all after the -u (both works). As you can see I prefer not to put any space.
-p is where you put your password.
-D is your database name. That’s a capital D.
-e this is where your query will go. It needs to be quoted (“). If it’s calling a stored procedure or stored function, you’ll need to use the CALL keyword, otherwise if it’s just a simple query don use the CALL keyword.

Posted in Database, Linux, MySQL | Comments Off on Calling a mysql query from linux or dos command line

Remove all svn directory

Subversion (SVN) sometimes clutter our source directory by creating .svn folder in each folder or sub folder that we version control.

The easiest way to erase them is by using a bash command:

1
find . -name ".svn" -type d -exec rm -rf {} \;
Posted in Linux, Version Control | Comments Off on Remove all svn directory