Sunday, May 10, 2026

Create a Bootable USB stick

For decades, Linux installations was done using CDs, later DVDs.  As the installation sizes increased and the popularity of CD/DVDs dropped the more recent releases are done via USB media.


With a source iso image, and an unmounted USB on /dev/sd1, you can create a bootable USB disk using the following command;

$ sudo dd bs=4M if=~/Downloads/ubuntu-24.04.1-desktop-amd64.iso of=/dev/sd1> conv=fdatasync  status=progress

 Take particular care to insure you've specified the right /dev/sd1 or your day may get much, much, much crappier.

 

Cheers.

 

Wednesday, May 6, 2026

Chaining Find Commands

For the better part of my career I used 'find' incorrectly, or at the very least very naively.  The '-exec' trickery eluded me for over a decade;

I often relied on running child processes or _worse_ saving results to a file to run subsequent command on.

For instance, if I wanted to examine log files that had 'error' in it, I'd fashion a command to open VI with the arguments of the result from a gr

ep command;

e.g. $ vi `grep -li error *.log`

 The command line would first execute the grep command, the results formed the arguments to the vi command.  Alternatively, I'd very occasionally
use xargs as an alternative.  Alternatively, to the alternative, I'd run the equivalent of the grep command and redirect the output to a file, then 'cat' the file contents as arguments to whatever command I wanted.

e.g.

$ grep -li error *.log > files.txt

$ vi `cat files.txt`

Clumsy, clumsier and often times clumsiest.  But, lacking an understanding of the '-exec' option, it was what I knew, got me where I needed to be, but was a source of embarrasement for someone who used Linux professionally for years.

 Then, about 8 years ago, I spent some time familiarizing myself with '-exec' and everyday tasks got a bit easier.  These past days I've been spending time on chaining '-exec' commands, something I wasn't familar with until recently.

Let's say you are asked to search a server for scripts that use 'ftp', not 'sftp', as a security audit.  A whole lotta scripts exist that use neither, a subset of them using ftp/sftp, and a subset of that subset exclusively use ftp (our desired file list).  An approach would be to first find all scripts that reference 'ftp', then filter out the ones that use 'sftp'.

$ find /src/scripts/ -type f -exec grep -l 'sftp' {} \;  #-- finds scripts referencing sftp

$ grep -L 'sftp' [filelist]; #--lists files w/o sftp expression

 You want to feed the results of the first command as arguments to the second command.  A clumsy approach (the one I used for years) would be:

$ grep -L 'sftp' `find /src/scripts/ -type f -exec grep -l 'ftp' {} \;`

 But, the equivalent can be accomplished by chaining '-exec' commands in a single command.

$ find /src/scripts/ -type f -exec grep -l 'ftp' {} \; -exec grep -L sftp {} \;

 Chained exec commands are executed left-to-right, each executed as child commands.  Subsequent '-exec' commands are only executed on files/lines that satisfy the previous '-exec' command.  So, 'grep -L sftp...' is only run on the results of the previous command (e.g. "grep -l 'ftp'...).  The end results is first finding all files containing 'ftp', then finding files that don't contain 'sftp'.  The output of both '-exec' commands, each on seperate lines, which can be confusing.  We can suppress the output from the first command by specifying '-quiet (or -q)' to the first grep command, as follows:

 $ find /src/scripts/ -type f -exec grep -lq 'ftp' {} \; -exec grep -L sftp {} \;

 Now, the resulting file list from the first exec is still passed to the subsequent exec and the output to stdout is representative of only the second command.


Sunday, May 3, 2026

Chaining Find Exec Commands for Quick Data Analysis

 Quick review of basic find command before getting to the content.

$ find . -name "*.txt" -exec grep -l dog {} \;

Executing commands via exec must end with \; and often use {} as a placeholder for each file that the find commands locates.  In the above example, imagine the command first locates the desired files, in this case files in the current and child directories that end with .txt.  These X filenames are then inserted/replacing the curly brackets.  Then, grep searches for 'dog' in each of those files and returns the filename of each file that matches.


Searching for a regex1 or regex2 in one pass can readily be accomplished by a single regex with one-pass file traversal.

$ find . -name "*.txt" -exec egrep -lo "reg1|reg2" {} \;

But, what if you're looking for matching files that include both regex1 and regex2?

 

Let's set up some simple files to play with, 3 files; cats.txt, dogs.txt, catsanddogs.txt

~/AdvancedFind$ more *.txt
::::::::::::::
catsanddogs.txt
::::::::::::::
cat
dog
::::::::::::::
cats.txt
::::::::::::::
cat
::::::::::::::
dogs.txt
::::::::::::::
dog

Finding files that contain 'cat' can be done by:

~/AdvancedFind$ find . -name "*.txt" -exec grep -li cat {} \;
./cats.txt
./catsanddogs.txt


Similarly, finding files that contain 'dog' can be done by:

~/AdvancedFind$ find . -name "*.txt" -exec grep -li dog {} \;
./catsanddogs.txt
./dogs.txt


You can 'chain' exec commands to satisfy finding files with 'cat' and 'dog' references.

~/AdvancedFind$ find . -name "*.txt" -exec grep -q cat {} \; -exec grep -l dog {} \;
./catsanddogs.txt

Files matching the first '-exec' command are passed to the second '-exec' command.  Notice the '-q' suppresses the first grep output, otherwise you'll get the output from both exec commands.

Similarly, you can find files that contain 'dog' that don't contain 'cat' can be done by:

~/AdvancedFind$ find . -name "*.txt" -exec grep -q cat {} \; -exec grep -L dog {} \;
./cats.txt
The '-L' means 'files without match', resulting in the first exec command identifying files that contain 'cat', the second exec command matching files that don't have a 'dog' reference.

 

Chaining exec commands can help perform quick data analysis using commonly available utilities.

Cheers.