The Text-User Interface

Using applications, configuring, problems
Message
Author
Bruce B

Simple math

#31 Post by Bruce B »

Simple math

Sometimes we want to perform simple math on the command line;

add, divide, multiple, subtract - then have the command prompt return after the command.

Introducing the external command: bc

bc is an extremely powerful calculator - powerful enough just using it could become a study in and of itself

Introducing: shift

shift is an internal bash command. It moves the variable string from right to left. Here is an example:

args = these are my arguments

$1 : these
$2 : are
$3 : my
$4 : arguments


The 'shift' instruction makes this change

args = are my arguments

$1 : are
$2 : my
$3 : arguments


Note how $1 disappeared and the other arguments are re-designated right to left.

Code: Select all

case ${1} in

	a*)  shift ; echo ${1}+${2}  | bc -l ;;
	d*)  shift ; echo ${1}/${2}  | bc -l ;;
	m*)  shift ; echo ${1}\*${2} | bc -l ;;
	s*) shift ;  echo ${1}-${2}  | bc -l ;;
	*) echo "a*dd | d*iv | m*ul | s*ub" ;;

esac
You've been introduced to; the case statement, shift, bc, | and echo

Curly braces {}

{ : begin
} : end

In this example, the curly braces are way overdone, we use them to make sure bash doesn't misinterpret where a variable ends. The $ says where it starts, but where does it end?

Is the variable $1 or is it $1- ?

The curly braces define ${1} as exclusive from any character immediately following.

The wildcard *

In this case statement, anything which starts with the letter a is a match because of the wildcard *

a, add, and advertise all mean the same thing.

If our first argument does not start with a,d,m,s ; the * at the end does match, and prints out a message and returns our command prompt.

This simple, even simplistic script does what it's made to do and even handles floating point math.

We use $1 to determine if we want to add, divide, subtract or multiple. I use the shift command mostly for demonstration. We could also not shift and use arguments $2 and $3 for processing the math. Makes sense? I hope.

Usage examples

math a 8 81
math d 124 2
math s 9 3
math m 1024 1024


Running totals:

double click the result and paste it into your next calculation

The purpose is . . .

. . .making things easier when we want simple math

Mandatory Assignment

Make a new utility called math by using our easy copy and paste method; (newsh)

Practice with it some

~

Chapter 32 - Simple math
Last edited by Bruce B on Mon 06 Jul 2009, 14:48, edited 1 time in total.

Bruce B

From image file to floppy disk

#32 Post by Bruce B »

From image file to floppy disk

Don't do exercises in this chapter unless you want and have reason to do the exercises.

A floppy disk is a physical object which we cannot download. We can of course download a floppy image.

First thing to do after downloading the imagefile.img is check its size with the ls command, using the -l switch, like this:

ls -l imagefile.ext

If the size is 1474560, it's likely ready to use.

If it is smaller, then use file to learn more, maybe it's compressed with bzip2, or something else, file will tell you:

file imagefile.ext ; if output is;

bzip2 compressed data, . . .

There you have it, it needs to be decompressed prior to use

bzip2 -d imagefile.ext

Then, again;

ls -l imagefile.ext

If byte size is 1474560, this is the size we generally expect prior to copying to floppy.

You can run file again and see what file thinks of it

file imagefile.ext

We know the name of our image file, what's the name of our floppy device?

Considering how Puppy changes, I dare not say, lets see if we can learn from Puppy.

cat /etc/fstab ; if you see something like the line below, Puppy thinks your floppy is /dev/fd0, so that's what we will use.

Code: Select all

/dev/fd0      /mnt/floppy  auto     noauto,rw              0 0
More on our dd (copy / convert) command. To copy the image file to the floppy disk, we could;

dd if=imagefile.ext of=/dev/fd0

if : infile
of : outfile

If we used our noggins, we put the floppy disk in the drive before running the command.

dd by default fails on errors, I think this is what we want, because if our outfile, contains errors we want to know about it and probably not use that floppy disk, (our outfile)

Suppose we want to give dd more exacting and explicit instructions. We could tell it to behave differently, according to our specifications.

We know the size of the file : 1474560

The default sector size for a floppy is : 512 bytes

Our new calculator 'math' will tell us how many sectors.

math d 1474560 512

answer is 2880

Our modified image to floppy command could become:

dd if=imagefile.ext of=/dev/fd0 bs=512 count=2880

If we planned more image to floppy copying, we could make a very simple script;

Code: Select all

#!/bin/bash
# filename : image2floppy
[ ! $1 ] && echo Missing argument && exit
dd if=$1 of=/dev/fd0 bs=512 count=2880
To make a respectably fair erase on a floppy disk containing sensitive information;

Code: Select all

#!/bin/bash
# filename : erase-floppy
dd if=/dev/zero of=/dev/fd0 bs=512 count=2880
dd if=/dev/random of=/dev/fd0 bs=512 count=2880
Destructive commands

I think it imperative to discuss destructive scripts. The above two script examples will irreversibly destroy any existing data on the floppy disk.

If you distribute your work, take the few minutes necessary and make some conditional checks as a part of your script.

We could advise the user the existing data will be destroyed and get permission FIRST.

We could optionally also offer to mount the disk and display the contents FIRST.

Doesn't this go without saying? The answer is unfortunately, a resounding NO!

Assignment - just read the chapter, which you've just done.

~

Chapter 33 - From image file to floppy disk

Bruce B

top

#33 Post by Bruce B »

Chapter 34 - top

Part of the curriculum in this series is introducing you to various command line utilities. In this chapter, I introduce you to top.

Assignment - open mrxvt and type top, then enter.

( q key to quit )

This is the end of your introduction to top. I have nothing to say about it, because there is something better.

htop

We will install a much more useful (yet quite small) utility called htop.

After you have installed htop, repeat the above assignment;

open mrxvt and type htop, then enter

It should be obvious to you why I've nothing to say about top and added htop.

I'll leave it to you to learn htop and read the text man page.

I do however . . .

. . . wish to teach you one aspect of htop, because it can get you out of trouble with a locked up application. And the technique described below is not particularly intuitive.

Suppose an application locks up and uses all available X resources. There is a GUI application somewhere in the menu to kill the offending application. But the GUI is so locked up, you cannot even access the menu.

I've seen posts where the Ctrl+Alt+Backspace key is the recommended way to leave X as if it were the standard way of operating Puppy. I cringe.

Left-Ctrl+Left-Alt+F2 will give you a terminal without crashing X or the application.

After logging in to your new terminal, run htop.

In htop, highlight the offending application. Then the F9 key, try and shutdown the offending application in this order;

15 SIGTERM

if that doesn't work, then;

9 SIGTERM

After closing the offending application, close htop and optionally logout of the terminal by typing exit.

Then;

Left-Ctrl+Left-Alt+F3 to return to your X session.

The instructions here probably won't have full meaning until you download and install htop.

Assignment - Please consider installing htop as highly recommend
  • 1) download htop.zip

    2) using mc, place htop and htop.txt in their appropriate directories

    3) open htop and familiarize yourself with it

    4) practice leaving X to a terminal and returning to X as described

    5) practice using htop for the purpose of conceptualizing how it is used to close an offending X application from the TUI
~

Chapter 34 - top
Attachments
htop.zip
contents: binary file - htop, man page - htop.txt
(40.71 KiB) Downloaded 1861 times

Bruce B

Install Medit with Midnight Commander

#34 Post by Bruce B »

Chapter 35 - Install Medit with Midnight Commander

In this chapter, we will practice using some Midnight Commander features. Also, install a great text editor / programmers editor called 'Medit'.

Medit isn't included with Puppy, but it is a part of its Official Repository.

We will do everything with Midnight Commander from downloading the medit archive to installing it.

Here are the steps:
  • 1) open mrxvt and mc

    2) connect to ftp.ibiblio.org with Midnight Commander, ( F9 + FTP Link . . .)

    3) type ftp.ibiblio.org then enter

    4) navigate the FTP server to this directory:

    /pub/linux/distributions/puppylinux

    5) bookmark it for future use ( left-Ctrl + \ )

    6) find this file in the /pet_packages-4 section: medit-0.9.2.pet

    highlight it; F5 to copy it from the FTP server to the directory of choice on your computer, (the pane not connected to the FTP server)

    When done: cd - to disconnect from the server

    7) if you installed the extension I posted in an earlier chapter, all you need do is highlight your local copy of medit-0.9.2.pet and it will open in a virtual archive

    8) using Midnight Commander's copy (F5), install Medit according to the archives directory tree, which in this case will be in /usr

    Previously we've been putting all files in our custom directories. In this lesson, I want to show you how to manually install a prepared pet package. So, we will use /usr according to the package tree.
If you do it right everything will be perfect, except your newly installed package will not be registered.

~

Chapter 35 - Install Medit with Midnight Commander . . .

. . . to be continued in Chapter 36

Bruce B

#35 Post by Bruce B »

Chapter 36 - listing files contained in a pet archive

In Chapter 35 we installed medit-0.9.2.pet. We don't however have a listing of the files installed. Not yet anyway.

When we make scripts or aliases we want to give them meaningful names which are easy to remember.

Suppose I pick a name like listpetfiles, it's descriptive, but a little long.

If we use tab-completion, all we need do is type listp, then hit the tab key for the rest of the file name.

Well, we are going to call our next script listpetfiles, if you want a different name, you don't need to rename it at all.

Introducing ln - making symlinks
  • Suppose you would rather use the name showpetfiles, you can make a 'symlink' like this:

    bin ( our alias for cd /root/bin )
    ln -s listpetfiles showpetfiles

    Doing so, it doesn't matter if you type showpetfiles or listpetfiles, the results are the same.
Introducing our script

Code: Select all

#!/bin/bash
# name: listpetfiles
# purpose: catalog contents of .pet archives
# to our personal doc directories

main() {

    var "$1"
    makelist

}

var() {

    [ ! $1 ] && echo "Argument missing" && exit
    [ ! -f $1 ] && echo "$1 doesn't exist" && exit
    echo "$1" | grep "\.pet$" >/dev/null
    if [ "$?" != "0" ] ; then
        echo -n "$1 doesn't seem to have a "
        echo ".pet extension quitting now"
        exit
    fi

    fn=`basename $1 .pet`
    outdir="/root/doc"

}

makelist() {


    <${fn}.pet gzip --decompress | tar --list \
    | tee ${outdir}/${fn}.txt


}


main "$1"

Script explanation
  • Another function based script

    The function var is used for sanity checking variables and setting variables
[ ! $1 ]
  • is a test to see if $1 does not exist. [ is a test command, ! means not , ] signals end of test
    our test is true if there is no command line argument, the subsequent commands execute, because the condition is true
[ ! -f $1 ]
  • -f says we are looking for a file with the same name as the content in $1
    ! means not

    if the filename in $1 does not exist the test is true and the subsequent commands execute
echo "$1" | grep "\.pet$" >/dev/null
  • here we pipe the argument $1 to the grep command by using echo. we are looking to see if arg1 ends in .pet

    we don't want on screen output so we direct the output to the device >/dev/null

    running the command therefore displays nothing
if [ "$?" != "0" ] ; then
  • this command followed the grep pipe. grep either found .pet at the end of the argument or it didn't

    if grep found .pet at the end of the file, it exited with an exit code of 0, meaning it is true that the end of the text string in $1 ends in .pet

    in this test, if we receive anything other that a 0, a true condition, it is true that the text string in $1 doesn't end with .pet and the 'then' portion of the if statements execute

    if we get through the sanity checks, we start processing
fn=`basename $1 .pet`
  • in this scenario, our argument $1 is medit-0.9.2.pet

    the basename $1 .pet command strips out the .pet extension

    the backticks ` ` are used to fill the variable with data

    the contents of $fn are : medit-0.9.2

    later we make a file called medit-0.9.2.txt
outdir="/root/doc"
  • earlier we decided to keep the course's document files in /root/doc, we define our destination directory as /root/doc

    The makelist function, explanations

    When the last command in var finishes, it returns to main to see if there are more commands, there are, main says: makelist
<${fn}.pet gzip --decompress | tar --list \
  • <${fn}.pet says to (re)direct contents of the file to the right
    We are not piping, we are redirecting to the external file gzip it's command to decompress the file

    (a pet file is a tar.gz file)

    Things generally come apart in the reverse order they went together.

    It went together like this: first the tar, second the gzip.

    To take it apart, first the gzip, then the tar.

    We pipe the gzip decompression to tar, we tell tar to list the contents, meaning the file names and directory names.

    Our \ character simply says, the next line is part of the command
| tee ${outdir}/${fn}.txt
  • We pipe to tee. tee sends the output to two different places. (1) the screen and (2) the specified file.

    This is the last command in the function makelist. The programming flow then goes back to main for its next instruction. There is not one and our program terminates.
~~~~~~~~~

Note on passing variables. We passed arg 1 to main. main passed it to var. We didn't pass arg 1 to makelist. We didn't need to because we used the fn variable which is available to our functions without a need to pass it to the functions, (after fn as been defined).

The result of running the command listpetfiles medit-0.9.2.pet is we have a complete record of all the changes made when we manually installed medit-0.9.2.pet in a text file called /root/doc/medit-0.9.2.txt

This record can be used if we want manually uninstall it.

More importantly, this is (hopefully) a good exercise in learning more about shell scripting.

Chapter assignment - as you please - script is attached

~

Chapter 36 - listing files contained in a pet archive
Attachments
listpetfiles.zip
shell script : listpetfiles
(502 Bytes) Downloaded 1868 times

Bruce B

#36 Post by Bruce B »

Chapter 37 - Test your learning

Barry K wrote a very useful script called probepart, this is a utility all 'command line' Puppians should know about.

Also you want to know about a companion script probedisk

Usage:

probepart
probepart -m (for listing in megabytes)

Exercise:

Run probepart and see what it does

Open the probepart script and read it, it's well written and well commented. It's not too short and not too long. About 100 lines including comments and blanks. You won't be able to understand it completely, so don't expect yourself to.

Just see how much of it you do understand and the command portions you recognize, based on what you've learned so far.

Hint:

which probepart to locate the file

double click the which output, to select and copy to a clipboard

$guieditor (paste)

Note: in open source programming, we often share our work in a community with other programmers. Among other things 'commenting' is very important. We can often see what another programmer does, but without comments, we may not know why.

~

Chapter 37 - Test your learning

Bruce B

Commenting your scripts

#37 Post by Bruce B »

Chapter 38 - commenting your scripts

In this chapter we will make a script to mount an iso file. The emphasis here is commenting. I will over do the commenting beyond what most programmers would do. One reason I've not been commenting our scripts is because in the forum posting using the code function, I preserve the formatting but I can't control color. In this post we forsake the important indentation for the purpose of commenting. The comments are in gray and the commands are in green.

#!/bin/bash

# function main

main() {

# list of main's commands

var "$1"
mountiso "$1"
displayfile
umountiso

}

# function var

var() {

# check for arg1, if not, display message and exit

[ ! $1 ] && echo "Argument missing, exiting" && exit

# if arg1 is not a file name, show message and exit

[ ! -f $1 ] && echo "$1 doesn't exist" && exit

# get an available loop device

lodev=`losetup-FULL -f`

# check if an available loop device was found, by using exit code
# from grep, hide output, then check exit code

echo $lodev | grep /dev/loop >/dev/null
[ "$?" != "0" ] && echo "Problem finding available loop device" && exit

# define our mount point in a variable

mntpnt="/mnt/iso"

# does our mount point exist?
# if not make it

[ ! -d $mntpnt ] && mkdir $mntpnt

# last command in function, automatically returns to main for next command

}

# function mountiso

mountiso() {

# setup the iso file on the loop device

losetup-FULL $lodev "$1"

# mount the iso file

mount-FULL -t iso9660 -o ro $lodev $mntpnt

# function umountiso

umountiso() {

# this function occurs when mc closes, when mc closes
# mc returns to the directory it was opened from

# unmount the iso file

umount-FULL $mntpnt

# free the loop device

losetup -d $lodev

}

# function display file

displayfile() {

# using midnight commander
# code execution halts until mc is closed

mc $mntpnt

}

# call to main and pass $1 to main

main "$1"

This is far more detailed commenting than you are likely to use or encounter. But if code were commented as well as this, it would be a 'piece of cake' for the next programmer to pick it up and work with it.

I've attached the script to the post, including comments and indents. Please download it and open it with geany or medit. Either of these editors highlight syntax and you will see how easy it is to read the bash script with an editor of this type.

If you have a iso file to mount, run the script

mtiso <filename>

~

Chapter 38 - Commenting your scripts
Attachments
mtiso.zip
script mtiso
(829 Bytes) Downloaded 1890 times

Bruce B

#38 Post by Bruce B »

Chapter 39 - mtsfs

In Chapter 38 we made a well commented script for easily mounting, viewing, working with and unmounting .iso files

The assignment for this chapter is:

Test mtiso and satisfy yourself it is a good script, if satisfied, use it as the template for making another script designed for mounting squashfs filesystems.

bin ( cd /root/bin )
cp mtiso mtsfs
$guieditor mtsfs &


make the necessary changes to the new file mtsfs

hint: the -t (type) parameter for an iso file is iso9660

the -t parameter for a .sfs archive is squashfs

~

Chapter 39 - mtsfs

Bruce B

Conditional expressions for integers

#39 Post by Bruce B »

Chapter 40 - Conditional expressions for integers

A lot of programming is about checking conditions. If this condition, we do this. It that condition we will do that. Or else we will do something different.

I think it's dawned on you by now, often times a programming routine simply makes a true or false check, as the basis for the decision what to do next.

Here I will introduce some basic bash math comparison operators

Code: Select all

[ "$1" -gt "$2" ] && echo "$1 is greater than $2"
[ "$1" -lt "$2" ] && echo "$1 is less than $2"
[ "$1" -eq "$2" ] && echo "$1 equals $2"
[ "$1" -ne "$2" ] && echo "$1 does not equal $2"
[ "$1" -ge "$2" ] && echo "$1 is greater than or equal to $2"
[ "$1" -le "$2" ] && echo "$1 is less than or equal to $2"
The 'echo' pretty much says what the operator does. In this routine we can have more than one true or false condition, because it runs from top to bottom, without branching.

For now, just remember this phrase, 'condition checks and branching'

bash knows what you entered as command line arguments. It also knows how many arguments you entered. $# is the number of arguments.

Before running the tests we could make sure sufficient number of arguments were entered, which would be two arguments

Code: Select all

[ "$#" -lt "2" ] && echo "insufficient number of arguments" && exit
Once again the true/false test. If it is true there are -lt ( less than ) two arguments, the commands execute, printing a message on screen and exiting the program

Our program only works on integers. We could make a filter to catch most times a user didn't enter an integer, like this:

Code: Select all

echo $1 $2 | grep [abcdefghijklmnopqrstuvwxyzAB\
CDEFGHIJKLMNOPQRSTUVWXYZ~!@_]>/dev/null \
&& echo "You must use integers" && exit
This sanity check is partial, it doesn't check for every wrong character. The reason why is some characters have special meaning and are hard to grep. So we will just do a little bit of sanity checking.

Putting our snippets in a logical order:

Code: Select all

[ "$#" -lt "2" ] && echo "insufficient number of arguments" && exit
echo $1 $2 | grep [abcdefghijklmnopqrstuvwxyzAB\
CDEFGHIJKLMNOPQRSTUVWXYZ~!@_]>/dev/null \
&& echo "You must use integers" && exit
[ "$1" -gt "$2" ] && echo "$1 is greater than $2"
[ "$1" -lt "$2" ] && echo "$1 is less than $2"
[ "$1" -eq "$2" ] && echo "$1 equals $2"
[ "$1" -ne "$2" ] && echo "$1 does not equal $2"
[ "$1" -ge "$2" ] && echo "$1 is greater than or equal to $2"
[ "$1" -le "$2" ] && echo "$1 is less than or equal to $2"
The exercise for this chapter is copy and paste the code. You can use newsh or fun. It doesn't matter.

You must be mindful of one thing. The two \ at the eol, must NOT have any white space to their right.

Hint: I've found keeping exercises is very helpful for reference. Suppose you forget an operator used in this session and you also forget the filename. But you can remember a phrase.

bin
grep "is greater" *


This command will show you every instance of 'is greater' along with the filename in your current directory. With the power of grep, you effectually have a catalog of your work.

~

Chapter 40 - Conditional expressions for integers

Bruce B

#40 Post by Bruce B »

Chapter 43 - some common Linux compression utilities

bzip2
gzip
zip


I'm attaching a less common compression utility in this post, called lzma, you probably don't have it. I compressed it as a bzip2 file.

Download it, to unpack it;

Midnight Commander, this time use the menu F2 to, practice learning how it toggles compression and decompression on a bzip2 file

Destination is /root/bin

For a matter of interest: In most cases bzip2 compresses tighter than gzip.

I've found the Linux zip compresses about the same as gzip - but zip doesn't delete the target after compression.

lzma compresses tighter than any of the three aforementioned. So I want you to have lzma. And you will need it for the next chapter.

~

Chapter 43 - some common Linux compression utilities

Bruce B

#41 Post by Bruce B »

Chapter 43 - Ispell

Ispell is an easy to use text interactive spell checker to enhance your GUI environment, making it even better than it already is.

To check a document ispell <filename>

To check spelling on a few words with keyboard input ispell

Some theory, about spell checkers.

You don't want the biggest dictionary for spell checking documents. A medium size dictionary is best because the big one has so many uncommon words, it might not flag a typo, if the typo happens to be spelled same as a rare word.

If you are good speller, a dictionary which doesn't make a lot of suggestions is also fine.

---------------

I compiled this spell checker to correspond with our directories.

Source file location was here: http://ficus-www.cs.ucla.edu/geoff/ispell.html

Should you prefer to do your own compile. The compile is easy, but there are some oddities, so read the documentation and think.

Installation of this package


mv ispell.tar.lzma.zip ispell.tar.lzma

forum won't allow the lzma extension, please consider this an exercise in frustration and I won't to it again.

lzma -d ispell.tar.lzma
tar xvf ispell.tar

install files according to the included README


Chapter 43 - Ispell

Bruce B

ls command

#42 Post by Bruce B »

Chapter 44 - ls command

Sorry, no chapters the last few days, I've been down with the flu. These chapters require more of me than a serious flu allows. I think I'm back!

Here we go; I introduce the ls command. A very basic and essential command.

The ls command without switches will give you a sorted five column directory display of all your 'not-hidden' files and directories, providing you don't have names longer than 15 on a (typical) 80 column
display. ( did you catch that? )

ls will determine the number of sorted columns displayed by the longest file name or sub-directory name in the current.

With this understanding, you might want to limit the length of your files.

Using ls' switches, I'll introduce the ones we plan to use, but there are many more, to see them;

ls --help

Code: Select all

Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).

  -A, --almost-all           do not list implied . and ..

  -d, --directory            list directory entries instead of contents,
                                    and do not dereference symbolic links

  -F, --classify             append indicator (one of */=>@|) to entries

  -l                              use a long listing format

  -1                             list one file per line

Exit status:
 0  if OK,
 1  if minor problems (e.g., cannot access subdirectory),
 2  if serious trouble (e.g., cannot access command-line argument).

-----------------------------

Note: -A, -d and etc are command line arguments, I also call them switches because of the -, which says in effect 'switch behavior'.

When type ls, we get our wide listing, and we can't tell the difference between a directory or a file. (unless we have color enabled, but we've not got there yet)

Let's make an alias to change behavior

alias l='ls --almost all --directory --classify'
# plus user arguments appended when running above alias

You can put the new alias in /etc/profile.local or /root/.bashrc

This alias switch --classify places a / at the end of the directory name, thus differentiating between a file, as you can see by the description

~

Chapter 44 - ls command

Bruce B

user script an ls enhancement

#43 Post by Bruce B »

Chapter 46 - user script an ls enhancement


lsf is short for ls find

lsf is a user made utility for finding files in your current directory by merely typing in portions of the file name. It accepts two arguments.

In /usr/bin lsf du gives us these possible files, because each file has the text string du

aseqdump*
db_dump*
du*
gsf-vba-dump*
gtk-query-immodules-2.0*
hexdump@
isodump*
objdump*
objdump86*
pango-querymodules*
pcprofiledump*
winedump*

lsf ^b gives: this list, because they all start with b
basename@
bc*
bcc*
bdftops*
bf_compact*
bf_copy*
bf_tar*
bison*
blinky*
blinkydelayed*
bochs*
bochs-dlx*
bogofilter*
bogolexer*
bogotune*
bogoupgrade*
bogoutil*
bxcommit*
bximage*
bzcmp@
bzdiff
bzegrep@
bzfgrep@
bzgrep*
bzip2recover*
bzless@
bzmore

lsf ^b c gives:

bc*
bcc*
bf_compact*
bf_copy*
bochs*
bochs-dlx*
bxcommit*
bzcmp@
bzip2recover*

( note @ means symlink , * means real executable file )

Here is lsf, the script

Code: Select all

if [ $2 ] ; then
    ls --classify --directory * \
    | grep $1 | grep $2
    exit
elif [ $1 ] ; then
    ls --classify --directory * \
    | grep $1
else
    echo "lfs : usage up to two"
    echo "search criteria"
fi
New for us is the keyword elif. We can't use if two times as a 'keyword' in the same if statement. We can use elif multiple times after the first if.

Code: Select all

count    keywords
1)         if
many)   elif
1)         else
1)         fi
many)   then one for each if or elif
True conditions call for 'then' executions. False conditions are ignored.

Is else true of false? It can be either, depending if any conditional tests above were true or false. If any were true, else if false. If all were false, else is true.

Can you see why I tested $2 before $1?

If $2 is true, $1 will be true. This is also why I exited $2 after running the commands.

Unrelated Reminder: grep ^matches first character of line. grep $ matches last character of line.

Assignment: download, install, practice and try and understand the file. More to come!

~

Chapter 46 - user script an ls enhancement
Attachments
lsf.zip
(271 Bytes) Downloaded 1814 times

Bruce B

#44 Post by Bruce B »

Chapter 47 - formatting output

A programmer or power user (you) should know the ls command quite well. Here is a bit more training

ls outputs in columns, sorted ascending down each column from left to right. If filenames are too long, we don't get as many columns. The column view shows a lot of files for the space used, but doesn't give many file details.

Code: Select all

ash            dd          getopt      mount-FULL        stty
autologinroot  delgroup    grep        mv                su
awk            deluser     gunzip      ncurses5-config   systool
bash           df          gzip        ncursesw5-config  tack
bashnewer      df-FULL     hostname    netstat           tar
bash-puppy     dlist_test  infocmp     nice              tic
bunzip2        dmesg       infotocap   ntfs-3g           toe
busybox        dpkg-deb    ip          pidof             touch
busybox.1st    dumpkmap    ipaddr      ping              tput
busybox.bak    e3          ipcalc      ping6             true
bzcat          e3em        iplink      pipe_progress     tset
bzip2          e3ne        iproute     ps                tst
captoinfo      e3pi        iprule      psf               umount
cat            e3vi        iptunnel    ps-FULL           umount-FULL
chattr         e3ws        kill        pwd               uname
chgrp          echo        last        readlink          uncompress
chmod          ed          ln          README-mount.txt  usleep
chown          egrep       loadkeys    reset             uuidgen
clear          false       login       rm                waitmax
compile_et     fdflush     ls          rmdir             zcat
cp             fgrep       lsattr      rpm
cp-FULL        find        mk_cmds     sed
cpio           gawk        mkdir       setserial
csh            get_device  mknod       sh
ls -l, lots of file information but the number of files is limited by the number of available lines on our terminal.

Code: Select all

-rwxr-xr-x 1 root root  14996 2007-10-18 18:45 setserial
lrwxrwxrwx 1 root root      4 2009-04-29 19:29 sh -> bash
-rwxr-xr-x 1 root root  12092 2007-10-22 03:14 sleep
-rwxr-xr-x 1 root root  47728 2007-10-18 18:38 sort
lrwxrwxrwx 1 root root      7 2009-04-29 19:29 stty -> busybox
lrwxrwxrwx 1 root root      7 2009-04-29 19:29 su -> busybox
-rwxr-xr-x 1 root root  15708 2007-10-18 18:45 systool
-rwxr-xr-x 1 root root 122656 2007-10-18 18:39 tack
-rwxr-xr-x 1 root root 188208 2007-10-18 18:39 tar
-rwxr-xr-x 1 root root  39584 2007-10-18 18:39 tic
-rwxr-xr-x 1 root root  26492 2007-10-18 18:39 toe
-rwxr-xr-x 1 root root  27080 2007-10-18 18:38 touch
-rwxr-xr-x 1 root root   8356 2007-10-18 18:39 tput
lrwxrwxrwx 1 root root      7 2009-04-29 19:29 true -> busybox
-rwxr-xr-x 1 root root  30972 2007-10-18 18:39 tset
-rwxr-xr-x 1 root root    457 2008-12-27 11:48 tst
-rwxr-xr-x 1 root root   2461 2007-04-21 17:11 umount
-rwsr-xr-x 1 root root  26948 2007-10-18 18:38 umount-FULL
-rwxr-xr-x 1 root root  11944 2007-10-18 18:38 uname
lrwxrwxrwx 1 root root      7 2009-04-29 19:29 uncompress -> busybox
lrwxrwxrwx 1 root root      7 2009-04-29 19:29 usleep -> busybox
-rwxr-xr-x 1 root root   3944 2007-10-18 18:43 uuidgen
-rwxr-xr-x 1 root root  16336 2008-03-15 20:07 waitmax
lrwxrwxrwx 1 root root      4 2009-04-29 19:29 zcat -> gzip
In the example below, we simply remove some displayed data from our ls long listing, by using the cut utility. For purpose of demonstrating 'cut'.

ls -l | cut -b 30-100 gives this, instead of the listing above

Code: Select all

  14996 2007-10-18 18:45 setserial
      4 2009-04-29 19:29 sh -> bash
  12092 2007-10-22 03:14 sleep
  47728 2007-10-18 18:38 sort
      7 2009-04-29 19:29 stty -> busybox
      7 2009-04-29 19:29 su -> busybox
  15708 2007-10-18 18:45 systool
 122656 2007-10-18 18:39 tack
 188208 2007-10-18 18:39 tar
  39584 2007-10-18 18:39 tic
  26492 2007-10-18 18:39 toe
  27080 2007-10-18 18:38 touch
   8356 2007-10-18 18:39 tput
      7 2009-04-29 19:29 true -> busybox
  30972 2007-10-18 18:39 tset
    457 2008-12-27 11:48 tst
   2461 2007-04-21 17:11 umount
  26948 2007-10-18 18:38 umount-FULL
  11944 2007-10-18 18:38 uname
      7 2009-04-29 19:29 uncompress -> busybox
      7 2009-04-29 19:29 usleep -> busybox
   3944 2007-10-18 18:43 uuidgen
  16336 2008-03-15 20:07 waitmax
      4 2009-04-29 19:29 zcat -> gzip
Excercise

type cut --help (review help)

see how other programmers find usage for cut

cd /etc
grep --files-with-matches "cut " *

view files that match and note cut usage

~

Chapter 47 - formatting output

Bruce B

#45 Post by Bruce B »

Chapter 48 - more formatting

Important Lectures and Theory

Basic categories of common and core utilities:

1) full version utilities

2) cut down utilities (which Puppy uses a lot of them

3) non-existent utilities - some scripting lessons you encounter will have you use an occasional utility which Puppy doesn't have. Not a problem, because you can troubleshoot it with the which command

4) utilities some scripting lessons won't let you use, because they don't trust you as root. Not a problem for us, is it?

------------------

Puppy has for all its history used many of the cut down versions of utilities. The reason why is obvious, to keep the distribution small by saving many megabytes over the larger utilities, man and info pages.

No, you cannot simply start replacing utilities on a one for one basis for the full versions.

The BusyBox utilities may not support the input switches and features we want. Just as important, they don't output exactly the same as the full versions, the predictive text formatting Puppy uses won't be right.

And by not using the BusyBox utilities in the right places, you can cause Puppy to make dumb decisions or even fail to boot.

Remember back to an earlier lesson about the PATH statement. Search left to right. We are at the end of the search for safety. If we put full featured utilities in our personal bin directory /root/bin, they will only be used if no match was found.

Here, I show you how to use full featured utilities in your personal directory with your personal scripts.

After finishing this lesson you will have three new full featured files:

/root/bin/tr
/root/bin/cut
/root/bin/head


In order for them to be used in the script, they need to be called by their full name. Our script's purpose is to find out how much physical memory your computer, (as if you didn't know already). Nevertheless, it will display it for you.

I'm calling the script mypc01, because I'd like to evolve it numerically, into something which gives even more useful information, and provides learning opportunities for you.

Let's look at the script.

Code: Select all

#!/bin/bash
utildir="/root/bin"
echo
kb=`< /proc/meminfo ${utildir}/head -n 1 \
| ${utildir}/tr --squeeze-repeats " " \
| ${utildir}/cut --delimiter=" " --fields=2`

echo " My computer has $kb Kb fixed RAM"
echo
echo " How many megabytes is $kb Kb?"
echo

#mb=`expr $kb / 1024`
#mbsell=`expr $kb / 1000`

mb=$(($kb/1024))
mbsell=$(($kb/1000))


echo " If division by 1024 we have $mb Mb"
echo " If division by 1000 we have $mbsell Mb"
echo

Note our variable utildir, now our full featured utilities will be used by this and probably other scripts in the future.

Note the arithmetic calculations. Which are correct? You will see both in use

Assignment required

Download utils.tar.gz, extract contents to /root/bin

Practice with the script and try and understand it.

~

Chapter 48 - more formatting

Bruce B

#46 Post by Bruce B »

Chapter 49 - Eliminating trailing white space

I had a lengthy script, which ran very successfully. I modified it from time to time. Then one little change and it stopped running. I went over and over the change and couldn't find a thing.

I went over every aspect of the script and still could not find the trouble. I opened it with a hex editor to view things which a text editor wouldn't show and still didn't find the cause.

I eventually thought maybe if it wasn't anywhere in the printing characters, it was likely a problem caused by non printing characters.

In the vast majority of cases when your scripts don't do as intended the problem is in the printing characters. The problem I describe is very rare and maybe shouldn't even be mentioned . . .

. . .but I suppose if it happened to me, it might happen to you. Also, one thing we have very little use for in our scripts, text documents and web pages is trailing white space.

The only files we ever want to remove trailing white space on are text files. Scripts, and html files are text files.

For starters in building this script, let's see how to tell if the intended file is an actual text file. file will tell it if it is.

file index.html, says: HTML document text
file updatedb, says: Bourne-Again shell script text executable

we can use grep's return code to see if it is safe to remove trailing spaces

~~~~~~~~~~~~~~


line 1 : file $1 | grep " text" >/dev/null
line 2 : [ x$? = x0 ] && echo $1 is a text file


line 1 : file processes the file in $1, we pipe the output to grep, grep looks for this text string" file" and we redirect the output to the black hole >/dev/null

grep gave bash an invisible return code based on if it found the string " file", we use the return code in line 2

line 2 : we test the return code to see if it matches 0. Earlier I showed arithmetic comparison operators. The = is not for arithmetic, it's more for string comparisons. When making comparisons we never want to compare one string with a blank. By using the x, either side of the string comparison are assured of having some kind of value as a place holder.

~~~~~~~~~~~~~~

String comparison - not arithmetic

Does x0 == x0 ? If true it is a text file

Earlier I used quotes, like this:

[ "$?" = "0" ] && echo $1 is a text file


The quotes serve the same purpose as the x - you're developing you own style.

We will work more on our script in the next chapter

~

Chapter 49 - eliminating trailing white space

Bruce B

#47 Post by Bruce B »

Chapter 50 - Introducing 'notrail'

notrail strips trailing tabs and spaces from text documents. This includes scripts and html files. It also saves the originals

Code: Select all

#!/bin/bash
main() {

	var "$@"
	process "$@"

}

var() {

	[ ! $1 ] && echo "missing filespec" && exit

	savedir=/var/notrail
	[ ! -d $savedir ] && mkdir $savedir


	subdir=`date "+%Y%m%d-%H%M"`
	savedir=${savedir}/$subdir

	[ ! -d $savedir ] && mkdir ${savedir}

	[ ! -d $savedir ] && echo "$savedir doesn't exist, exiting" && exit

	logfile="${savedir}/LOG_FILE.LOG"

}

process() {

	echo "Working, please wait . . ."

	for i in "$@" ; do

		[ ! -f $i ] && continue

		file $i | grep  text >/dev/null
		if [ "$?" == "0" ] ; then
			mv $i $savedir
			<${savedir}/$i sed 's/[ \t]*$//'>$i
			echo "Cleaned $i" >> $logfile
		else
			echo "$i not a text file">>$logfile
		fi

	done


	echo
	echo "Original files saved in $savedir"
	echo "Directory contents: "
	ls $savedir


}


main "$@"
sed

A new utility introduced here is 'sed', a stream editor. You won't learn it overnight, but you will learn it in time. Try and not be overly anxious with this one.

I've provide some support material for you

A link from where I got the snippet used in this script, Handy one liners for sed

Also, use the forum search to see how others have used sed.

~

Please download in install attachment notrail

Edited: Attachment removed for a better utility, see Chapter 80 and download cleanf.zip



Chapter 50 - Introducing 'notrail'
Last edited by Bruce B on Tue 04 Aug 2009, 08:34, edited 1 time in total.

Bruce B

#48 Post by Bruce B »

Chapter 51 - I really want to keep these chapters moving. Lots more to come.

I've been down sick bad. Apart from finding energy when sick, the creative aspects needed aren't there when I want them.

I want you to know I'm still with it.

-----------------

If any have questions, or problems, please PM me.

Bruce B

#49 Post by Bruce B »

Chapter 51 - swapf

Guess what we are going to do? That's right. Make another script.

Hint: If you haven't noticed by now, the way to learn how to script and program, is by scripting and programming. You just need a few people to help you get started.

Some times we want to swap files, one file with the other. It takes about three command line operations. If for purpose of testing you swap back and forth a few times, it takes several commands.

The basic command line ( and program flow is like this )

rename file A to a non existent name
rename file B to file A's original name
rename, the renamed file A to the original name of file B


We already learned it's good to have some sanity and error checking, and it's good to have some on screen feed back.

When a command prompt merely returns, without feedback, it leaves sort of a feeling of a vacuum, did it do like we wanted? With good screen feedback, any wondering is diminished greatly.

~~~~~~~~~~

We now have a rough idea what we want our script to do. (0) give a short yet descriptive name, (1) swap file names, (2) do some error checking before doing the swap, (3) give us on screen feed back.

This is an easy script, so lets get started

SCRIPT OUTLINE

Code: Select all

main() {

}

vars() {

}

before() {

}

after() {

}
swapem() {

}

main $1 $2
Note what I did above, was put everything I want my script to do according to descriptive functions. All I have to do is fill out some simple commands in the appropriate functions, watch how easy it is. Even complex programming can be simple when broken down into small parts.

The actual script

Code: Select all

#!/bin/bash

main() {

    vars $1 $2
    before $1 $2
    swapem $1 $2
    after $1 $2

}

vars() {

    [ ! $2 ] && echo "Insufficient arguments" && exit
    [ ! -f $1 ] && echo "Filename $1 doesn't exist, exiting" && exit
    [ ! -f $2 ] && echo "Filename $2 doesn't exist, exiting" && exit
    echo $1 | grep " ">/dev/null
    [ x$? = x0 ] && echo "Come on, spaces in file names are for Windows users" && exit
    echo $2 | grep " ">/dev/null
    [ x$? = x0 ] && echo "Come on, spaces in file names are for Windows users" && exit

}

before() {

    echo ""
    echo "Before swapping filenames:"
    ls -l $1
    ls -l $2
    echo ""

}

after() {

    echo "After swapping filenames:"
    ls -l $1
    ls -l $2
    echo ""
}

swapem() {

    mv -i $1 $1.$$
    mv -i $2 $1
    mv -i $1.$$ $2

}

main $1 $2
Script notes and comments

We could name Windows spaced files, but I don't want to in this script.

$$ is the pid of the child process

If $1 is busybox, (as an example), it gets named like this: busybox.3189, odds are extremely in our favor no such file name exists. Extra insurance is the use of mv's -i (--interactive) switch to prevent an unintentional overwrite.

When we want to use a command line argument such as $1 or $2 we need to pass it to each function which uses it. Or set an internal variable, which we didn't do in this example.

With the on screen feedback, you can easily verify the files were swapped properly by comparing the before and after times, dates and sizes and relative positions on the screen.

Note: your functions can be called in any order main says. The 'after' function came before the 'swapem' : it doesn't matter.

~

Chapter 51 - swapf


Instructions: download and install the attached script, if you want it.
Attachments
swapf.zip
(445 Bytes) Downloaded 1237 times

Bruce B

#50 Post by Bruce B »

Chapter 52 - more grep

I noted this question in the beginners section,
  • "I can't find an easy way to change the computer name, I can view it in the system information viewer but cant find how to change the details."
The computer 'name' is puppypc and the GUI application hardinfo doesn't say how it arrived at that name.

If we understand that the directory /etc mainly holds system configuration information, we have a good place to start looking.

We would want to find out which files have the word puppypc in them to get an idea where to make the changes we want to make. Here is some practice using grep on the command line.

cd /etc : stay in this directory for the exercises below

grep puppypc * : look in all files, case sensitive search, display instances with file names

grep -i puppypc * : look in all files, case insensitive search, display instances with file names

grep -il * : as above but display only the file names

grep -r puppypc * : search in subdirectories also
or
grep -R puppypc * : search in subdirectories also

grep -ilr puppypc * : is valid, meaning we can mix our switches

Please practice these commands. The command line user needs to be well versed with the basics and intermediate usage of grep.

The examples I gave above use the short switches, which is what we mainly use on the command line. In scripts the long hand makes the script easier to read and we only type the script commands one time, (hopefully). Although short switches are frequently used in scripts, but it's a nice practice to use long names.

Short and long switches used in this chapter for examples

-i , --ignore-case
-r , --recursive
-R , --recursive
-l , --files-with-matches


~

Chapter 52 - more grep

Post Reply