Basic Shell (Console) operation for beginners

Booting, installing, newbie
Message
Author
jamesbond
Posts: 3433
Joined: Mon 26 Feb 2007, 05:02
Location: The Blue Marble

#31 Post by jamesbond »

Thanks Bruce. One can always learn new things every day here - even from the Beginner section :D
Fatdog64 forum links: [url=http://murga-linux.com/puppy/viewtopic.php?t=117546]Latest version[/url] | [url=https://cutt.ly/ke8sn5H]Contributed packages[/url] | [url=https://cutt.ly/se8scrb]ISO builder[/url]

Bruce B

#32 Post by Bruce B »

When this topic started, I thought I'd leave others talk about shell
scripting. I'd contribute by teaching how customize the shell with aliases
and functions.

Before making a new command of any kind, make sure the command
name doesn't exist. We are going to make a new command called mnt.
What you would want to do is type in mnt to make sure no such
command already exists.

Enter this on the command line:

# alias mnt='cd /mnt'

Then run mnt. You should now be in the /mnt directory

Then using the command separator ; run the following command:

# mnt;rox

This should open an instance of rox in the /mnt directory. It is faster
and easier than using the rox interface to get there.

~

Bruce B

#33 Post by Bruce B »

Introducing ~/.bashrc

Each time we open a terminal emulator, bash reads /root/.bashrc and
executes all the commands.

Presently, I'm focused on getting us started with aliases to change
directories. Once these aliases have been written into .bashrc, we never
have to enter them again. They become a part of our shell commands,
seamlessly.

I want everything easy. For this reason I use very cryptic commands. I
also try and keep things a bit consistent. Commands to edit files start
with ed

alias edrclocal='mp /etc/rc.d/rc.local'
alias edprofile='mp /etc/profile'

You get the idea, cryptic, but somewhat intuitive.

More lecture on sourcing

.bashrc is sourced when bash opens

Bash programmers sometimes get confused by not understanding what
does and doesn't get carried down, up or sideways to another emulator.

Puppy's /etc/profile sets up the working environment. It is not a shell
script and needs to run at very low level, it runs by sourcing and before
bash even comes into play.

A sourced file is simply a flat text file with commands in it. It doesn't
need to have an executable bit set. It doesn't need #!/bin/bash on the
top line.

For a practice test, make a file with this line.

echo foo bar

Then run the file like this:

. filename


~

Bruce B

#34 Post by Bruce B »

Open ~/.bashrc with a text editor and add the following commands. You
don't need the comments, so delete them as wanted. Make sure to always
leave on linefeed at the end of your file after manually editing.

Code: Select all

# shows full path at prompt
export PS1='[\w] '

# shows current directory
#export PS1='[\W] '

# moves back one directory
alias ..='cd ..'

# moves back two directories
alias ...='cd ../..'

# moves back three directories
alias ....='cd ../../..'

# to return to a saved directory, a script is needed
# but not yet included in this post
alias u='. /tmp/uu~'

# returns to last directory
alias b='cd -'

# refreshes .bashrc
alias rf='. ~/.bashrc'

# opens .bashrc for editing, the resources it
# use text editor of YOUR choice
alias eda='mp ~/.bashrc;. ~/.bashrc'

Changes will take effect on opening the next emulator.

More to come, soon.

~

Bruce B

#35 Post by Bruce B »

I advise keeping all your scripts in their own directory. I use /root/bin

If the directory of your choice doesn't exist, make it.

To add it to the path statement open /etc/profile and find the PATH= line

Add your directory to the end like this :/root/foobar

The script presented here is called acd, it means 'add current directory'
(to .bashrc)

It is a way of bookmarking your favorite directories.

If you are in /usr , then type acd and it will add usr as a command to cd
to /usr


alias usr='cd /usr'

If you are in /usr/lib it will add lib as the command to cd to /usr/lib, you
may not want that as your command name, if not then run the
command like this

acd usrlib

alias usrlib='cd /usr/lib'

If you are in /mnt/sda2, acd will add this command to your .bashrc file

alias sda2='cd /mnt/sda2'

If you want another name, run it like this: acd a2

alias a2='cd /mnt/sda2'

Code: Select all

#!/bin/bash
[ $1 ] && name=$1
[ ! $1 ] && name=`basename $PWD`
echo alias $name="'cd $PWD'">>/root/.bashrc
</root/.bashrc grep "$name"
From here on you can build your command line 'bookmarks' with great
ease. It becomes especially usefully with long directory paths. Look what
the command doors does on my computer.

alias doors='cd /mnt/sdb1/mp3/doors'

Attached is the actual file acd.zip, if you'd rather not make it.

~
Attachments
acd.zip
(236 Bytes) Downloaded 1655 times

Bruce B

#36 Post by Bruce B »

acd (add current directory) explained

Here is the complete script

Code: Select all

#!/bin/bash
[ $1 ] && name=$1
[ ! $1 ] && name=`basename $PWD`
echo alias $name="'cd $PWD'">>/root/.bashrc
</root/.bashrc grep "$name"

#!/bin/bash
  • tells Linux it is a shell script executable
    /bin/bash tells which interpreter I want to use, also its location
[ $1 ] && name=$1
  • [ is a command called test
    a good unix user would not put a command in a filename
    it is little things like what Windows users do that can
    cause us problems with our scripts, unless we know [ is
    an actual command

    $1 is a command line argument or parameter.
    $1 would be the first command
    $2 would be the second command

    ] is not a command. It is syntax used to say "end of test"

    [ $1 ] is simply a way of 'testing' to see of the user entered a command
    line argument

    && is a conditional operator. If the condition is true, it executes the
    command on the right, if false nothing happens

    name is a variable. The = sign is the end of the variable. Anything to the
    right of the = sign gets moved into the variable

    If I entered the text foobar on the command line, after the executable
    name, then $1 would be true and the variable name would contain the
    text foobar
[ ! $1 ] && name=`basename $PWD`
  • Either I entered text on the command line or I didn't.

    ! is an operator which means not

    [ ! $1 ] tests to see if not $1 - in English it asks if I did not enter a
    parameter.

    If I didn't then a true condition exists and the operator && will execute
    the command on its right.

    name=`basename $PWD`

    name is as already explained a variable, it can contain a variety of data,
    the data in it is not static.

    $PWD is an environment variable. It changes its contents to match our
    current directory.

    If we were in /usr/lib/firefox then $PWD would contain the data /usr/lib
    /firefox

    If we typed basename $PWD on the command line it would echo firefox

    In this usage, basename strips out the parent directories

    We want to move, shove the output of basename $PWD into our variable,
    this is where the backticks come in. We need them in order to force the
    output from right to left into the variable.
echo alias $name="'cd $PWD'">>/root/.bashrc
  • echo means to repeat and is a very common command

    our goal here is to stuff the following command at the tail of .bashrc

    alias firefox='cd /usr/lib/firefox'


    name and PWD are both initialized variables

    We don't want the variables, we want the data they contain. To
    accomplish this we add the $ to the front of the variable.

    echo $PWD would print /usr/lib/firefox
    echo $name would print firefox

    I need the single quotes in the command I want to write to .bashrc

    The single quote also has a meaning and prevents the expansion I need,
    but using the double-quotes allows it.

    Let's look at the command again:

    echo alias $name="'cd $PWD'">>/root/.bashrc

    I do not want the command printed to the screen, also known as standard
    output, I want it printed to the file /root/.bashrc

    The >> redirects the output to where I send it, which is /root/.bashrc

    The >> appends the file

    A > would delete all existing data in .bashrc and leave me only with the
    command.

    >, >> and < are called redirection symbols, they are instructions to
    redirect output
</root/.bashrc grep "$name"
  • The < redirects the entire /root/.bashrc file to grep

    grep is a search utility, as the data is being redirected through grep, it
    searches for the contents of $name which is firefox, in our example.

    All lines containing 'firefox' will be displayed to standard output, our
    monitor.

    Its purpose is merely to verify that the command acd did what we wanted.
Code repeated, does it make more sense now? I hope!

Code: Select all

#!/bin/bash
[ $1 ] && name=$1
[ ! $1 ] && name=`basename $PWD`
echo alias $name="'cd $PWD'">>/root/.bashrc
</root/.bashrc grep "$name"
~

Bruce B

#37 Post by Bruce B »

From the commands I made to put into .bashrc

alias u='. /tmp/uu~'

In this post contains the support script.

Code: Select all

#!/bin/bash
echo cd $PWD>/tmp/uu~
The script name is uu - when we want to save a directory for fast access
later, type uu.

To return to the directory, at any time, type u

It is attached as uu.zip if you'd rather have it that way.

There are also two builtin commands pushd and popd, these can be very
useful in scripts, but not often used, because not often needed. I leave
the user to learn about them.

help pushd
help popd


~
Attachments
uu.zip
second uu.zip upload - this points to /tmp, the first pointed to /dev/shm
download the new one if you downloaded the /dev/shm one
(170 Bytes) Downloaded 1684 times
Last edited by Bruce B on Tue 08 Mar 2011, 09:37, edited 1 time in total.

Bruce B

#38 Post by Bruce B »

Often when we make a directory, we want to change to the newly made
directory.

As the reader has learned by now there are many, many ways to make
life easier by using the command line.

I want to show an example of how to add a function to your .bashrc file.

This function will make and new directory and change to the newly made
directory.

Code: Select all

ndir() {

    if [ $1 ] ; then
        [ ! -d $1 ] && mkdir $1
        cd $1
    else
        echo Missing argument
    fi

}
To use you would type in

ndir foobar

You can also add more commands by using the ;

ndir foobar;rox

Functions can be defined in a few different ways. The example above
shows how I do it. Here is a template

Code: Select all

functionname() {

    echo

}
There has to be a command of some sort or bash will get mad at you, so
for the template, I used echo.

~

Bruce B

#39 Post by Bruce B »

When to use .bashrc and when to use scripts.

When you run a script, your .bashrc aliases and functions are not
available in the script. This is usually, if not always, to your advantage.
You don't want some alias you forgot about interfering with your script.

Here is an example:

alias rm='rm -i'


This alias means that you will be asked to verify each deletion.

You may not want that interaction in your script, considering the aliases
don't exist, you use the rm command as you want without interference.
Your script will behave as written.

Some distributions add the .bashrc commands below by default,
considering how hard it is to undo mistakes, I recommend the aliases
below.

BTW - we are done with the change directory instructions.

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

This will cause an interactive command where you have to confirm the
actions.

Suppose you know you want to remove every file in a directory and don't
want to confirm everyone, you can escape the alias with a backslash

\rm *


Here is another example of aliases I use

alias xms='xmms *.mp3 &'


Remember 'doors' does cd /mnt/sda2/mp3/doors

As fast as I can type doors;xms, the music I want to play starts playing.
This is more convenient than the mouse movements required to open
xmms and do the same thing.

Also, I could have an alias like this:

alias playdoors='xmms /mnt/sda2/mp3/doors/*.mp3 &'


or

alias playdoors='cd /mnt/sda2/mp3/doors;xmms *.mp3 &'

~

Bruce B

#40 Post by Bruce B »

Sometimes your .bashrc file can become very large. I decided to give a
command which will allow you to easily search it.

alias grepbashrc='<~/.bashrc grep -i'

[~] grepbashrc usr
alias usrbin='cd /usr/bin'
alias usrlib='cd /usr/lib'
alias usr='cd /usr'
alias usrlocal='cd /usr/local'
alias usrlocalbin='cd /usr/local/bin'
alias usrshare='cd /usr/share'

Here I refine the search results by piping again through grep

[~] grepbashrc usr | grep local
alias usrlocal='cd /usr/local'
alias usrlocalbin='cd /usr/local/bin'
[~]

The general rule is, you can add commands to your alias, this is
demonstrated above.

Shell expansion within the alias itself is, well, not beginning level stuff.

If you need to expand variables, the function is the better choice.

~

Bruce B

#41 Post by Bruce B »

I have a sincere concern I want to express.

PupGeek started this topic with a great deal of interest.

Now I notice I'm the only one posting. I feel bad about that. The reason
why I feel bad is because I think unintentionally took other's interest in
posting. This is not OK with me.

I'm asking, "Can we please make this a community project. Anyone
interested please contribute and ask questions. We learn from each other
and we teach other."

If this doesn't happen, and I'm the only one, I will probably let it drop
off to page two.

Please. Our power is in community.

~

tlchost
Posts: 2057
Joined: Sun 05 Aug 2007, 23:26
Location: Baltimore, Maryland USA
Contact:

#42 Post by tlchost »

Bruce B wrote:I have a sincere concern I want to express.

PupGeek started this topic with a great deal of interest.

Now I notice I'm the only one posting. I feel bad about that. The reason
why I feel bad is because I think unintentionally took other's interest in
posting. This is not OK with me.
~
You want to consider that many of us value your posts....and may not want to "jump in the middle" and disrupt your train of thought.

Thanks for the information.....and please do not stop.

Thom

Bruce B

#43 Post by Bruce B »

tlchost wrote: You want to consider that many of us value your posts....and may not want
to "jump in the middle" and disrupt your train of thought.
I didn't consider that. Now I have a thought to work with I didn't have
before. To grow we need each other.

And I'd still feel better about this if PupGeek and others would resume their
interest. I'll wait and see.

Thanks

~

jpeps
Posts: 3179
Joined: Sat 31 May 2008, 19:00

#44 Post by jpeps »

Bruce B wrote:
tlchost wrote: You want to consider that many of us value your posts....and may not want
to "jump in the middle" and disrupt your train of thought.
I didn't consider that. Now I have a thought to work with I didn't have
before. To grow we need each other.

And I'd still feel better about this if PupGeek and others would resume their
interest. I'll wait and see.

Thanks

~
We're sitting on the sidelines monitoring for any malicious code :)

Bruce B

#45 Post by Bruce B »

Bash programming flow

The lines are read from top to bottom and executed in that order.

Often we write our programs line1, line2, line3 and etc.

When done, if we did it right, our program works.

We write a program in order to do something for us. In most cases I write
programs because I want to solve problems. The problem might be how
to make something complex - simple.

We find in writing good programs we want to implement conditional check
and branches. Otherwise we can write a destructive program.

It is very important to know exactly what you want your program to do,
before writing it.

Think about it for a while and write notes before you program.

I'll make a demo program to show you how to make conditional checks
and branches.

Progname: bkuproot
Purpose: to make a backup of /root files on a separate partition
I need to:
make sure the partition is mounted
that there is sufficient space on the partition
I'll use the zip utility for my backup
I'll skip the space check to make my example easier
zip will bomb out with an on screen error if there wasn't enough space


My primary purpose here is actually to demonstrate how to make a
conditional check and branch, this should be easy. I'm ready to code.

Code: Select all

#!/bin/bash

DESTPART=/dev/sda2
DESTDIR=rootbkup
FILENAME=bkuproot.zip
Please note: by using variables, we make our script easily portable, and
we can make them easy to modify. We merely change the data in the
variable. We don't have to search the entire script.

Let's first make sure /dev/sda2 is mounted

Code: Select all

</proc/mounts grep $DESTPART>/dev/null
/dev/null is Linux' black hole, everything we redirect to /dev/null disappears.

By redirecting the output to /dev/null we eliminate all on screen output.

Our search criteria is /dev/sda2

Grep will not tell us if /dev/sda2 is mounted. It tells us if it found our
criteria. If it found our criteria, we know it is mounted, because grep will
give us an error code of 0 if it found the text.

What we are going to test for is grep's error code. The error code is found
in the variable $? If grep found the text then we have error 0

Now we introduce the first part of an if statement.

Code: Select all

if [ "$?" = "0" ] ; then
    [ ! -d $DESTPART/$DESTDIR ] && mkdir  $DESTPART/$DESTDIR

See how by using variables we can change the file merely by modifying
the easy to find variables at the top of the file. No searching and replace
necessary.

-d means we are looking for a directory

If a backup file already exists, let's delete it

Code: Select all

[ -f $DESTPART/$DESTDIR/$FILENAME ] && rm $DESTPART/$DESTDIR/$FILENAME


-f says we are looking for a file

Now let's make the new backup file. Note: many users make their
backups by putting dates in the file names. For our purpose, I'll keep it
more simple.

Now we are ready to make our backup

Code: Select all

zip -r9y $DESTPART/$DESTDIR/$FILENAME /root 
We don't have to check for the existence of /root, if it doesn't exist, we
have serious problems to work out.

zip is the command

-r9y means recurse /root, use maximum compression and preserve links,
don't convert to the files they reference

When you write your script you have to learn about the utility you want to
use, in this case zip

zip --help will show its options

Here is our safety branch:

Code: Select all

else
    echo "$DESTPART is not mounted, no changes made"

we terminate our if statement like this:

Code: Select all

fi
Now I'll put it all together, see if you can read it and understand it

Code: Select all

#!/bin/bash

DESTPART="/dev/sda2"
DESTDIR="rootbkup"
FILENAME="bkuproot.zip"

</proc/mounts grep $DESTPART>dev/null
if [ "$?" = "0" ] ; then
    [ ! -d $DESTPART/$DESTDIR ] && mkdir $DESTPART/$DESTDIR
    [ -f $DESTPART/$DESTDIR/$FILENAME ] && rm $DESTPART/$DESTDIR/$FILENAME
    zip -r9y $DESTPART/$DESTDIR/$FILENAME /root 
else
    echo "$DESTPART is not mounted, no changes made"
fi  
Most of my scripts look like a C programmer who escaped from a mental
ward who is trying to write in bash.

This time I think I actually followed bash conventions.

Namely using uppercase variables, quoting the variable data, and
making the script easily changed and portable.

If our partition is not mounted we have a false condition at the
beginning of our if statement. No commands execute. if looks for else and
executes it which is merely an on screen message to the user.

Also, notice the indents, they tell us what commands run within the
statement. It makes the code easier to work with and read. Especially
helpful when statements are nested and very long.

By the way this program has not been tested. If anyone can find errors,
I'll agree to owe them a nickel.

EDITED: You guys and gals are not reading well. The program contains a serious error. Please find it so you can be owed a nickel.

~

~
Last edited by Bruce B on Wed 09 Mar 2011, 04:26, edited 1 time in total.

Bruce B

#46 Post by Bruce B »

What is easier to read?

With variables

Code: Select all

#!/bin/bash

DESTPART="/mnt/sda2"
DESTDIR="rootbkup"
FILENAME="bkuproot.zip"

</proc/mounts grep $DESTPART>/dev/null
if [ "$?" = "0" ] ; then
    [ ! -d $DESTPART/$DESTDIR ] && mkdir $DESTPART/$DESTDIR
    [ -f $DESTPART/$DESTDIR/$FILENAME ] && rm $DESTPART/$DESTDIR/$FILENAME
    zip -r9y $DESTPART/$DESTDIR/$FILENAME /root
else
    echo "$DESTPART is not mounted, no changes made"
fi  
Without variables

Code: Select all

#!/bin/bash

</proc/mounts grep /mnt/sda2>/dev/null
if [ "$?" = "0" ] ; then
    [ ! -d /mnt/sda2/rootbkup ] && mkdir /mnt/sda2/rootbkup
    [ -f /mnt/sda2/rootbkup/bkuproot.zip ] && rm /mnt/sda2/rootbkup/bkuproot.zip
    zip -r9y /mnt/sda2/rootbkup/bkuproot.zip /root
else
    echo "/mnt/sda2 is not mounted, no changes made"
fi 
Obviously the one without variables is easier. But as explained earlier, the
one with variables in easily modified and more portable. Although your
text editor does accurate and fast search and replace if you didn't use
variables.

You can write your programs as you please. Either script does exactly the
same thing.

I tend to put my variables in lowercase, because it is easier for me to
read. Also, C convention uses lowercase variables.

When using variables, try and give them meaningful names.

~
Last edited by Bruce B on Thu 10 Mar 2011, 20:22, edited 1 time in total.

jpeps
Posts: 3179
Joined: Sat 31 May 2008, 19:00

#47 Post by jpeps »

maybe /dev/null. Worth a nickel?

Bruce B

#48 Post by Bruce B »

jpeps wrote:maybe /dev/null. Worth a nickel?
try again

jpeps
Posts: 3179
Joined: Sat 31 May 2008, 19:00

#49 Post by jpeps »

Bruce B wrote:
jpeps wrote:maybe /dev/null. Worth a nickel?
try again
Script will work from "/". Guess that's good enough, right?

Bruce B

#50 Post by Bruce B »

I think I've shown how to change directories easily at lightening speed.

Now I want to show how to find files much, much, much faster than the
computer can search itself and display the results on the screen.

We do it by using a database containing a list of every file on the
machine. I don't know if this script will work on Puppy frugal, it might. It
should, but I don't recall. On second thought, it has been tested on Frugal.

There are also other support scripts which aren't yet posted. This one only
builds the database.

I leave it to the user to review the script and try and figure out what it's
doing and why I've written certain things.

If something doesn't make sense, then ask, I'll explain.

The purpose of the script is to build a database of every file on the disk.
This database can be searched much faster than a big disk with many
partitions.

Code: Select all

#!/bin/bash

main() {

	vars
	updateroot
	updatemnt
	filedatabase

}

vars() {

	dbfile=/dev/shm/update.db
	destdir=/var/log
	
	# get list of directories off /
	rootdirs=`find / -maxdepth 1 -type d | cut -c 2-100 \
	| grep -v sys | grep -v 'lost+found' | grep -v mnt \
	| grep -v proc | grep -v dev | tr "\n" " "`
#	echo $rootdirs

	# get mounted filesystems
	mntdirs=`cat /proc/mounts | grep /mnt/ \
	| cut -d " " -f 2 | tr "\n" " "`
#	echo $mntdirs
	

}

updateroot() {


	echo > $dbfile

	for i in $rootdirs ; do
		echo "updating /$i"
#		nice --adjustment=+6 find /$i -mount -type f>>$dbfile 
		find /$i -mount -type f>>$dbfile 
	done


}

updatemnt() {

	for i in $mntdirs ; do
		echo "updating $i"
#		nice --adjustment=+6 find $i -noleaf -mount -type f>>$dbfile
		find $i -noleaf -mount -type f>>$dbfile
#		break
	done

}

filedatabase() {


	mv $dbfile $destdir

}


main

Post Reply