Basic Shell (Console) operation for beginners

Booting, installing, newbie
Post Reply
Message
Author
PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

Basic Shell (Console) operation for beginners

#1 Post by PupGeek »

Introduction:

In most cases, Puppy Linux is built to be easy to use and graphical wherever possible. There are times, however, when using the shell (Bash, commandline, terminal, etc) is necessary, more powerful, or can provide helpful information. I believe some basic knowledge of the shell is advantageous to all computer users, regardless of experience level. Note that I did not single out Linux users here, because I believe that Windows users should learn to use Windows command line too.

If you are putting together a software package or are having trouble running an application, the shell can be very helpful here. Most often, this is a dependency issue when trying to install a new application. I will use this thread to go over some shell basics so that you can solve these kinds of problems. I will also touch on basic shell scripting so that you can learn to add some automation to your software.

We should be using Puppy 4.2.1 (this will work for most versions, but for uniformity, lets use 4.2.1) and we will be putting together the ZynAddSubFx Software Synthesizer package. Trust me when I say that it is a lot less frustrating to learn this when you don't need it, than it will be when you do.
Last edited by PupGeek on Sat 03 Dec 2011, 01:33, edited 4 times in total.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

Part 1: Getting started

#2 Post by PupGeek »

Ok lets get started. First we need a program to install. I am choosing a software synthesizer called ZynAddSubFx. We will not be using any package manager, as it would defeat the purpose of this discussion. We are learning to use the commandline to diagnose and repair unresponsive programs. We need to find a repository that can be accessed with a browser. For this, I will use the Ubuntu repository. I am using Puppy 4.2 (Kernel 2.6.25.16) for this tutorial so I will go with the Dapper Drake version. You can click below to get there.

http://packages.ubuntu.com/dapper/

Now, we need to create a directory to work in. Choose a location for this directory and name it ZynZddSubFx. Remember where this location is so you can download the software directly to it. When you click on the link above, you will find yourself at a page that organizes packages by type. I have tabbed browsing capability, I recommend opening in new tabs from the context menu instead of simply clicking on items. From this page, click Sound, then scroll down and click ZynAddSubFx. On the ZynAddSubFx page, you should see a list of dependencies. We will be getting all of those, but for now, lets just scroll down and download ZynAddSubFx for i386 (assuming you are using a 32 bit puppy). You should come to a list of mirrors. Choose one and at the dialog, save it to disk, choosing your newly created directory.

Now open up that new directory and you should see the .deb file in there. Right-click anywhere within that window and in the 'window' submenu, choose 'terminal here'. this will open up a shell window for you set for that directory. Verify that you are in that directory by typing 'ls' at the # prompt. You should only see the .deb file you just downloaded. You will be extracting this .deb from the shell, but notice that the filename is rather long and easy to get wrong. We will be using a 'for' loop to help you here. Just type the following in

Code: Select all

# for i in `ls *.deb`; do undeb $i; shift; done
#
I know there was only one file in here but I used a for loop because in many cases, there will be several such files to do and this makes it much easier than typing long filenames. After executing the loop, you should find a usr directory along with the .deb file. Enter the following command in the shell that is opened while noting that I do not use a preceding '/' in the path.

Code: Select all

 
# usr/bin/zynaddsubfx
After entering that command, I get the following message:

Code: Select all

usr/bin/zynaddsubfx: error while loading shared libraries: libmxml.so.1: cannot open shared object file: No such file or directory
# 
If I had just clicked on an icon, it simply would have appeared unresponsive, so that is one way the shell can help you solve a problem. Now that we know that there is a missing library file, we can try to resolve it. Lets first start by using the ls command (for List) to try and locate it. Enter the following line in the shell:

Code: Select all

# ls usr/lib/libmxml*
ls: cannot access usr/lib/libmxml*: No such file or directory
#
As we can see, the missing library is not in the new directory so lets try the system directories next. Note the presence of the preceding slash in this path.

Code: Select all

ls /usr/lib/libmxml*
ls: cannot access /usr/lib/libmxml*: No such file or directory
#
There is nothing like it there either. This means we will have to download it so lets go back to the ubuntu repo. If you have kept your ZynAddSubFx package page up, you can select libmxml from the dependency list and proceed with downloading it. You may have to keep downloading dependencies until all are resolved and this is why I taught you the for loop. It makes it so much easier. When I get back, we will get to installing and testing our program to see if it works.

Edit: I tried to use the Hardy Heron packages, but I found out they require a newer GLIB, which can cause major problems if updated. I have decided to go with Dapper Drake packages instead.
Last edited by PupGeek on Sun 06 Mar 2011, 01:35, edited 4 times in total.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#3 Post by PupGeek »

Ok now that we have downloaded the missing library libmxml, lets run the for loop once more. This will extract all .debs in the directory. After that run the usr/bin/zynaddsubfx line again and see what happens.

That's right! You get the same error message about the same dependency! This is because we have not installed anything to your system directories ( those contained in the /usr directory ). We could simply copy them over if we'd like, but that can sometimes cause trouble, so I'd like to try a different method. We can use what are called "environment variables". Included in these environment variables are paths and library paths that Puppy is supposed to look in to locate commands and libraries. We can add the current directory to those from the command line, but the changes will disappear when the shell is closed. It is quite a handful to type that in every time we want to test our new program, so we will do this in a "shell script". A shell script is a text file that contains shell commands to be executed. Nearly all these commands are identical to typing them into the shell yourself. It adds convenience by executing all the commands within from just a single command. Let's begin by creating a new script called "Run" in your ZynAddSubFx/usr directory. Right click anywhere in the directory window, then in the "new" submenu, choose "script". When done, right click on it and "open as text".

As you can see, you have a blank page with the text "#!/bin/sh" as the first line. All shell scripts must begin with this line, as it identifies the shell to use for the script. Place your cursor at the end of that line and press enter a couple of times. We will begin by defining variables, including environment variables. Edit your new script so that it appears as below:

Code: Select all

#!/bin/sh

export APPDIR=`dirname "$0"`								# This defines the variable APPDIR as the directory this script resides #in
export PATH=$PATH:$APPDIR/bin								# PATH and LD_LIBRARY_PATH are environment variables
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$APPDIR/lib

# Note the format PATH=$PATH:$APPDIR/bin. This format defines PATH as the existing PATH appended by APPDIR/bin
# It is important that you include the existing PATH in the new definition so as not to overwrite what was already #there. 
# Also note that after being defined, all variables being used must be preceded by $.

# Now that our variables have been defined, let's try running the program

$APPDIR/bin/zynaddsubfx

Any text preceded by '#' within the script is called a comment and is placed there to help the user understand the script better. It is important to insert many comments as it can clarify the commands and why they are in the script.

Now enter your ZynAddSubFx/usr directory and open a new terminal there and type './Run' to run your new script and see what happens. Now its calling for libfltk. This means that it has now found the first dependency and that using the environment variables worked. Now it is missing another dependency. Lets download the fltk (pronounced "full tick") package and run the for loop in the old shell again. You may have to keep repeating this sequence until all dependencies are resolved, so I won't go over it again.
Last edited by PupGeek on Sun 06 Mar 2011, 18:25, edited 8 times in total.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#4 Post by PupGeek »

Ok, when all dependencies are resolved, you should get a gui for ZynAddSubFx. The first screen should offer you a choice of beginner or advanced interfaces -- choose one. If you click on the "VK" button it should bring up a virtual keyboard so that you can start playing notes (either by clicking on the virtual keys or by pressing keys on your computer keyboard). You should, at this point, hear something. Now, you might think we are done, but we are not. Try clicking on the 'instrument' menu and then 'show instrument bank' to see what happens. That's right, its blank and no matter how many times you refresh it, it stays blank. We will now solve this problem. We will further edit your 'Run' script to accomplish this. The beauty of packaging software like this is that, with a script you can redefine environment variables, place items in any directory and remove them when done. Nice and clean.

Edit your 'Run' script so it looks like the following:

Code: Select all

#!/bin/sh

export APPDIR=`dirname "$0"`								# This defines the variable APPDIR as the directory this script resides in
export PATH=$PATH:$APPDIR/bin								# PATH and LD_LIBRARY_PATH are environment variables
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$APPDIR/lib

# Note the format PATH=$PATH:$APPDIR/bin. This format defines PATH as the existing PATH appended by APPDIR/bin
# Also note that after being defined, all variables being used must be preceded by $.

ln -s `pwd`/share/zynaddsubfx /usr/share			# Add this line to your script


# Now that our variables have been defined, let's try running the program
$APPDIR/bin/zynaddsubfx

rm /usr/share/zynaddsubfx											#And this line too

Now type ./Run again and see what happens. This time, when you click on the 'instrument' menu and 'show instrument bank' you can refresh it and get some options in the drop down menu. For now, select an option and play around with it. We are still not done yet.
Last edited by PupGeek on Sun 06 Mar 2011, 02:42, edited 1 time in total.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#5 Post by PupGeek »

Ok, as I said, we still aren't done yet. Assuming that you are using Rox to navigate through directories, we are going to make this into a "Roxapp". A Roxapp is a directory that is linked to a script (called AppRun). When you click on this directory, it executes that AppRun script. Now right click on your 'Run' script and rename it to 'AppRun'. Now first, type ./AppRun into the shell and notice what happens. That's right, the same thing as when it was named 'Run'. Close or minimize the shell and back out of the directory containing your 'AppRun' script and notice that the icon for the usr directory has changed. Click on that icon. Now try to show your instrument bank and see what happened. It's back to being blank again. This is due to some code in the script. When we wrote the script, you may have noticed some strange stuff like `dirname "$0"` and `pwd`. These are examples of "Command Substitution". Command substitution is like a variable defined by the output of a particular command, and is placed in between backticks (`). You have seen an example of this in the 'for' loop we ran while installing dependencies (for i in `ls *.deb`). The command dirname "$0" is the current directory that the shell happens to be in (.). Unfortunately, you cannot use it when creating a symbolic link, as it doesn't work correctly. The command pwd is the present working directory, where you accessed the script. When you typed ./AppRun into the terminal, everything worked fine because `pwd` was the same directory in which the script was. When you clicked on the directory's icon, It failed because `pwd` was one level up and so the link was made incorrectly. Now how do we solve that? Well one idea is to use a full path, but we can do better than that, and make it a lot neater too. I will explain it further in my next section, but for now, lets give your Roxapp a new icon. Right click on your roxapp and 'look inside' it go to share then pixmaps and notice the icon and right click on it and select Copy. Remove the share/pixmaps/ from the path shown in the Copy dialog, and navigate back to the usr directory and you should see a copy of the icon. Right click on zynaddsubfx.xpm and rename to .DirIcon and it should disappear. In the meantime, rename your AppRun script back to Run so you will not run the script if you enter the usr directory again. If you click on the Eye in your toolbar, it should display hidden files, including your new .DirIcon file. When you navigate back out of your usr directory you should find that it has the new icon you just gave it.
Last edited by PupGeek on Sun 06 Mar 2011, 03:16, edited 2 times in total.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#6 Post by PupGeek »

Ok reenter your ZynAddSubFx/usr directory and we will now attempt to place all of its directories into a "squashfs" file. A squashfs is a compressed filesystem that is sort of like a tar.gz file. Unlike a tar.gz archive, a squashfs can be mounted and accessed without extracting its contents. This is a very useful feature and essential to all LiveCD Linuxes. You may have seen examples of this as .sfs modules for puppy. I like to use them in Roxapps because it makes them very neat and allows for absolute control over where directories are located, making the creation of links much more reliable (I call them Hassle-Free Roxapps because in making them, I try to resolve all dependencies). I know that we still have that issue with the instrument bank but this process should end up resolving that.

Lets begin our conversion by creating a new directory in ZynAddSubFx/usr. Lets call it ZynAdd. Move or copy your bin, lib, and share directories into it. If you moved them and try running your script now, it won't work. Close all your old terminals and open a new one in ZynAddSubFx/usr. Type the following line into the terminal:

Code: Select all

mksquashfs ZynAdd ZynAdd.roxfs
You should see a progress bar as it is creating the file and a bunch of verbose text when completed. After completion you should see a file named ZynAdd.roxfs. You can name the file and extension to your choice directly in the mksquashfs command. I like to use roxfs as the preferred extension for my roxapps. With that completed, we will now get to editing the 'Run' script to utilize the new roxfs.

Here is your current 'Run' script:

Code: Select all

#!/bin/sh

export APPDIR=`dirname "$0"`								# This defines the variable APPDIR as the directory this script resides in
export PATH=$PATH:$APPDIR/bin								# PATH and LD_LIBRARY_PATH are environment variables
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$APPDIR/lib

# Note the format PATH=$PATH:$APPDIR/bin. This format defines PATH as the existing PATH appended by APPDIR/bin
# Also note that after being defined, all variables being used must be preceded by $.

ln -s `pwd`/share/zynaddsubfx /usr/share			# Add this line to your script


# Now that our variables have been defined, let's try running the program
$APPDIR/bin/zynaddsubfx

rm /usr/share/zynaddsubfx											#And this line too

And you should edit it to look like this. Notice, I also edited the link creation line to use $APPDIR instead of `pwd`.

Code: Select all

#!/bin/sh


mkdir /mnt/ZynAdd														# Creates a working directory
mount -t squashfs -o loop `dirname "$0"`/ZynAdd.roxfs /mnt/ZynAdd #mounts the roxfs into the working directory

export APPDIR=/mnt/ZynAdd								# This defines the variable APPDIR as the working directory
export PATH=$PATH:$APPDIR/bin								# PATH and LD_LIBRARY_PATH are environment variables
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$APPDIR/lib

# Note the format PATH=$PATH:$APPDIR/bin. This format defines PATH as the existing PATH appended by APPDIR/bin
# Also note that after being defined, all variables being used must be preceded by $.

ln -s $APPDIR/share/zynaddsubfx /usr/share		# creates a link	


# Now that our variables have been defined, let's try running the program
$APPDIR/bin/zynaddsubfx

rm /usr/share/zynaddsubfx											
umount /mnt/ZynAdd													# This unmounts the roxfs after use
rmdir /mnt/ZynAdd														# Cleans up after itself

Now rename the script back to 'AppRun', back out of the directory and click on the icon to test it out.

If it is working, you may rename the directory from 'usr' to ZynAddSubFx, look inside it, and delete the ZynAdd folder, since it now uses the .roxfs instead. Notice that when it is not running, you will not find any evidence of it having been in your /usr or /mnt directories. If it crashes, however, the script never completes and directories and links will remain where they were placed and will have to be removed manually. I have now taken you from knowing nothing about the shell to making a Hassle-Free Roxapp. I hope this inspires you to learn more about the shell and scripting. It can place a lot of power in your hands. Good luck and enjoy.

Pupgeek
Last edited by PupGeek on Sun 06 Mar 2011, 04:26, edited 4 times in total.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#7 Post by PupGeek »

reserved

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#8 Post by PupGeek »

reserved

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#9 Post by PupGeek »

If anybody here wishes to share other tips regarding the shell and scripting please feel free to post them here. This is intended to introduce beginners to the shell and scripts so that they may begin experiencing the true power of Linux.


I recommend downloading some additional materials such as what I am posting below for explanations of the commands being used here, and to help make your experience more predictable.

http://tldp.org/LDP/GNU-Linux-Tools-Sum ... ummary.pdf

http://tldp.org/LDP/Bash-Beginners-Guid ... -Guide.pdf

There are many guides and other resources available if you go here:

http://tldp.org/guides.html


This thread was made with the intention of getting more enjoyment out of Linux. Let's keep it respectful and beginner-friendly. Have fun :D
Last edited by PupGeek on Sun 06 Mar 2011, 14:41, edited 2 times in total.

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

#10 Post by jpeps »

Nice presentation, PupGeek! I like your use of a script for setting up a test environment. Beginners might not know to add exec privileges to script, though.

Bruce B

#11 Post by Bruce B »

~
Last edited by Bruce B on Sun 06 Mar 2011, 19:28, edited 1 time in total.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#12 Post by PupGeek »

@jpep: Good point, but with the way I discussed creating a new script, it does that automatically. Anyway, for those who create a new script from within a text editor, you can use the chmod command, or right click > Properties to set exec privileges.

The chmod command to make a script executable is as follows:

Code: Select all

chmod 755 <filename.ext>
Last edited by PupGeek on Sun 06 Mar 2011, 23:08, edited 1 time in total.

User avatar
r1tz
Posts: 162
Joined: Thu 09 Sep 2010, 05:19
Location: In #puppylinux (IRC)

Re: Part 1: Getting started

#13 Post by r1tz »

Code: Select all

for i in `ls *.deb`
do
undeb $i
shift
done
http://mywiki.wooledge.org/ParsingLs
http://mywiki.wooledge.org/BashPitfalls ... .2A.mp3.29
so....

Code: Select all

for i in *.deb
do
undeb "$i" #It is a good habit to quote variables.
shift
done
Also, for

Code: Select all

 usr/bin/zynaddsubfx 
you can also use

Code: Select all

 ./usr/bin/zynaddsubfx 
gives the same results.

Edit your main post. I'll remove this.

I dont mean to step on your toes or anything, just hoping to share :)[/code]

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#14 Post by PupGeek »

This is not intended to be a complete programming introduction, it was meant to help people solve a problem they might have. As for the preceding "./" I did not want to be confusing people this early in the game ( "./" and "/" would look a bit too similar to me, at a glance, if I were a beginner). I had to be obvious because I wanted to be as concise as possible, as it was long-winded enough.

I do not enclose variables in quotes, because my experiences with earlier versions of BASIC yielded a lot of syntax errors due to that. I am trying to gently guide beginners to using the CLI, and make something work, not to enforce proper coding convention.

Honestly, I do not have a single problem with using ls in a command substitution. In fact, I have more problem with the inclusion of spaces and newlines in filenames, as, I feel, that is more against naming convention. When it comes to naming files, I like to treat spaces and newlines as illegal characters myself. Instead I use CamelNotation and dashes.

If the beginner becomes interested enough in coding, they can learn all about coding conventions. This is intended to be more of a survival guide -- a way to possibly fix a program that doesn't seem to execute. I only threw in making the roxapp so that the beginner could learn by making something work, rather than throw a bunch of text and rules at them.
Last edited by PupGeek on Sun 06 Mar 2011, 18:50, edited 1 time in total.

User avatar
Keef
Posts: 987
Joined: Thu 20 Dec 2007, 22:12
Location: Staffordshire

#15 Post by Keef »

Pupgeek:
I'm not sure it's plain how you initially made the first script:

eg right click in the directory, select 'New' then 'Script'.

I think this needs to be more explicit (I didn't realise it was there myself until I tried to find out how you had done it).

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#16 Post by PupGeek »

Thanks keef I completely spaced that out. :oops:

Anyways, I edited it to include that.

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

#17 Post by jpeps »

It can be helpful using something like "tree" to view what's present in the directory.

http://www.murga-linux.com/puppy/viewtopic.php?t=47657

User avatar
rjbrewer
Posts: 4405
Joined: Tue 22 Jan 2008, 21:41
Location: merriam, kansas

#18 Post by rjbrewer »

This subject belongs in the "How to" or "Users" sections;
not Beginners!!

Inspiron 700m, Pent.M 1.6Ghz, 1Gb ram.
Msi Wind U100, N270 1.6>2.0Ghz, 1.5Gb ram.
Eeepc 8g 701, 900Mhz, 1Gb ram.
Full installs

User avatar
r1tz
Posts: 162
Joined: Thu 09 Sep 2010, 05:19
Location: In #puppylinux (IRC)

#19 Post by r1tz »

This is not intended to be a complete programming introduction, it was meant to help people solve a problem they might have. As for the preceding "./" I did not want to be confusing people this early in the game ( "./" and "/" would look a bit too similar to me, at a glance, if I were a beginner). I had to be obvious because I wanted to be as concise as possible, as it was long-winded enough.
True enough :)
Honestly, I do not have a single problem with using ls in a command substitution. In fact, I have more problem with the inclusion of spaces and newlines in filenames, as, I feel, that is more against naming convention. When it comes to naming files, I like to treat spaces and newlines as illegal characters myself. Instead I use CamelNotation and dashes.
The reason not to use "ls" is because it wont have "inclusion of spaces and newlines in filenames". Also it looks more simple without the ls.
The quotes are necessary for inclusion of newlines/tabs/spaces.

So in order for the script to adapt to the filename and not the other way, it is better to have quote and not use ls.

PupGeek
Posts: 353
Joined: Sun 06 Sep 2009, 11:30

#20 Post by PupGeek »

I did not know you could leave the ls command out of the for loop and achieve the same result (I just checked that out and was surprised). Nice shortcut there, thanks.

With my Roxapp example, the script only deals with files that are essential to the program itself. Data files are handled from within the program. The script only sets up the program temporarily and cleans itself up when you are done using it.

As for quoted variables, they have always looked wrong to me... probably because of my earlier experiences, but it is nice to know that quoting a variable allows it to handle data containing spaces. I was wondering how to go about doing that. I don't like putting spaces in filenames and I know many coders don't either, but I guess I have to know how to deal with them if I'm going to code.

some of the biggest commands I have trouble with are grep, sed, and awk. I also have trouble with regular expressions (or at least, complex ones.... kinda like Algebra :) ). That's when it really starts to get confusing to me. I try to avoid those wherever I can.

@rj: I placed this in beginners because I wanted to let people know that, yes, even a beginner can learn to use the CLI. I'm sure there are beginners who are interested in this kind of stuff but may not be quite ready to leave the beginner's circle yet. This can ease them into a more advanced area.
Last edited by PupGeek on Sun 06 Mar 2011, 22:37, edited 1 time in total.

Post Reply