With all of the network configuration I’ve been doing lately, I’ve decided to set up a central syslog server that the routers and switches can log to. That will create a central place that I can look for warnings and errors that are occurring on these devices. It also makes it so I can save the logs for extended periods of time, and use normal Linux tools to search and parse through them.
For some reason, I found it difficult to find instructions on how to create a centralized syslog server. However, its incredibly easy. You just have to configure the Linux syslogd process to listen on a remote interface, then configure the logs like anything else in syslog. In CentOS, you just edit /etc/sysconfig/syslog and add a “-r” to the “SYSLOGD_OPTIONS” line. Then allow port 514 through your firewall from your router’s IP addresses.
On each router, set these global configuration commands:
logging facility local1
logging source-interface FastEthernet0/1
logging 10.0.0.123
On the syslog server, configure your /etc/syslog.conf with something like this:
## Router Logs
local1.* /var/log/routers/router-core.log
local2.* /var/log/routers/router-border.log
local3.* /var/log/routers/switch-1.log
local4.* /var/log/routers/switch-2.log
I also like to set up logrotate with this in /etc/logrotate.d/routers
/var/logs/routers/*.log {
weekly
rotate 52
compress
missingok
notifempty
}
Friday, October 16, 2009
Wednesday, May 27, 2009
ccde
• Routing TCP/IP, Volume 1, 2nd Edition
• Routing TCP/IP, Volume II
• MPLS and VPN Architectures, CCIP Edition
• MPLS Fundamentals
• Advanced MPLS Design and Implementation
• Definitive MPLS Network Designs
• Fault-Tolerant IP and MPLS Networks
• Traffic Engineering with MPLS
• QoS for IP/MPLS Networks
• Layer 2 VPN Architectures
• OSPF Network Design Solutions, 2nd Edition
• Optimal Routing Design
• BGP Design and Implementation
• Top-Down Network Design, 2nd Edition
• Troubleshooting IP Routing Protocols
• End-to-End QoS Network Design
• IP Quality of Service
• Network Management Fundamentals
• Voice-Enabling the Data Network
-rfc:
• Graceful Restart Mechanism for BGP
• BGP Route Reflection: An Alternative to Full Mesh Internal BGP (IBGP)
• A Border Gateway Protocol 4 (BGP-4)
• Capabilities Advertisement with BGP-4
• Autonomous System Confederations for BGP
• Use of OSI IS-IS for Routing in TCP/IP and Dual Environments
• IS-IS Mesh Groups
• The OSPF Not-So-Stubby Area (NSSA) Option
• Alternative Implementations of OSPF Area Border Routers
• OSPF Version 2
• Protocol Independent Multicast - Sparse Mode (PIM-SM):Protocol Specification (Revised)
• Anycast-RP Using Protocol Independent Multicast (PIM)
• The Generalized TTL Security Mechanism (GTSM)
• BGP/MPLS IP Virtual Private Networks (VPNs)
• Routing TCP/IP, Volume II
• MPLS and VPN Architectures, CCIP Edition
• MPLS Fundamentals
• Advanced MPLS Design and Implementation
• Definitive MPLS Network Designs
• Fault-Tolerant IP and MPLS Networks
• Traffic Engineering with MPLS
• QoS for IP/MPLS Networks
• Layer 2 VPN Architectures
• OSPF Network Design Solutions, 2nd Edition
• Optimal Routing Design
• BGP Design and Implementation
• Top-Down Network Design, 2nd Edition
• Troubleshooting IP Routing Protocols
• End-to-End QoS Network Design
• IP Quality of Service
• Network Management Fundamentals
• Voice-Enabling the Data Network
-rfc:
• Graceful Restart Mechanism for BGP
• BGP Route Reflection: An Alternative to Full Mesh Internal BGP (IBGP)
• A Border Gateway Protocol 4 (BGP-4)
• Capabilities Advertisement with BGP-4
• Autonomous System Confederations for BGP
• Use of OSI IS-IS for Routing in TCP/IP and Dual Environments
• IS-IS Mesh Groups
• The OSPF Not-So-Stubby Area (NSSA) Option
• Alternative Implementations of OSPF Area Border Routers
• OSPF Version 2
• Protocol Independent Multicast - Sparse Mode (PIM-SM):Protocol Specification (Revised)
• Anycast-RP Using Protocol Independent Multicast (PIM)
• The Generalized TTL Security Mechanism (GTSM)
• BGP/MPLS IP Virtual Private Networks (VPNs)
Saturday, May 23, 2009
find problems
First let me say that a complete format and reinstall will be necessary when your done doing forensics.
Probably good places to start looking would be to take a look at the apache/httpd logs for any abnormal error messages. Also look through the general system logs for anything suspicious. You should definitely download and run rootkit hunter and chkrootkit on the system, as there are a bunch of things listening as services that shouldn't be (like init for example), which makes a rootkit likely. If that's the case, then you may need to use a cd-based distro like knoppix-std or FIRE to do any further analysis.
You may have some luck looking those processes up by their process ID number in /proc//cmdline. If you find anything interesting there (like a path to the binary) take a look at the contents and see what you can find.
Probably good places to start looking would be to take a look at the apache/httpd logs for any abnormal error messages. Also look through the general system logs for anything suspicious. You should definitely download and run rootkit hunter and chkrootkit on the system, as there are a bunch of things listening as services that shouldn't be (like init for example), which makes a rootkit likely. If that's the case, then you may need to use a cd-based distro like knoppix-std or FIRE to do any further analysis.
You may have some luck looking those processes up by their process ID number in /proc/
Saturday, May 16, 2009
ssh
1. Generate a public/private key pair on the local machine
(ssh client): >
ssh-keygen -t rsa
(saving the file in ~/.ssh/id_rsa as prompted)
2. Just hit the when asked for passphrase (twice) for no
passphrase. If you do use a passphrase, you will also need to use
ssh-agent so you only have to type the passphrase once per session.
If you don't use a passphrase, simply logging onto your local
computer or getting access to the keyfile in any way will suffice
to access any ssh servers which have that key authorized for login.
3. This creates two files: >
~/.ssh/id_rsa
~/.ssh/id_rsa.pub
4. On the target machine (ssh server): >
cd
mkdir -p .ssh
chmod 0700 .ssh
5. On your local machine (ssh client): (one line) >
ssh {serverhostname}
cat '>>' '~/.ssh/authorized_keys2' < ~/.ssh/id_rsa.pub
or, for OpenSSH, (one line) >
ssh {serverhostname}
cat '>>' '~/.ssh/authorized_keys' < ~/.ssh/id_rsa.pub
You can test it out with >
ssh {serverhostname}
and you should be log onto the server machine without further need to type
anything.
If you decided to use a passphrase, do: >
ssh-agent $SHELL
ssh-add
ssh {serverhostname}
You will be prompted for your key passphrase when you use ssh-add, but not
subsequently when you use ssh.
(ssh client): >
ssh-keygen -t rsa
(saving the file in ~/.ssh/id_rsa as prompted)
2. Just hit the
passphrase. If you do use a passphrase, you will also need to use
ssh-agent so you only have to type the passphrase once per session.
If you don't use a passphrase, simply logging onto your local
computer or getting access to the keyfile in any way will suffice
to access any ssh servers which have that key authorized for login.
3. This creates two files: >
~/.ssh/id_rsa
~/.ssh/id_rsa.pub
4. On the target machine (ssh server): >
cd
mkdir -p .ssh
chmod 0700 .ssh
5. On your local machine (ssh client): (one line) >
ssh {serverhostname}
cat '>>' '~/.ssh/authorized_keys2' < ~/.ssh/id_rsa.pub
or, for OpenSSH, (one line) >
ssh {serverhostname}
cat '>>' '~/.ssh/authorized_keys' < ~/.ssh/id_rsa.pub
You can test it out with >
ssh {serverhostname}
and you should be log onto the server machine without further need to type
anything.
If you decided to use a passphrase, do: >
ssh-agent $SHELL
ssh-add
ssh {serverhostname}
You will be prompted for your key passphrase when you use ssh-add, but not
subsequently when you use ssh.
Saturday, May 9, 2009
Export and Backup Emails from Outlook to Gmail Online
It's possible to download emails from gmail into Outlook but is it possible to do it in reverse? Amit tells us we can in this step by step guide.
Step 1: Enable IMAP in your Gmail account and then
configure Outlook (or Outlook Express or Windows Live Mail) to sync
with your Gmail address via IMAP. Read this guide.
Step 2: Import your Outlook PST file into a Personal folder that is different from your default Gmail Inbox.
To import, click File -> Import And Export -> Import from another program or file. -> Next -> Personal Folder File (.pst)
-> Next.
Select the PST file that contains your email, then pick the email folders that you want to import in Outlook and click Finish.
Step 3: Select the Personal folders that you want to backup online and copy them your Gmail Folder in Outlook.
In the Folder List, right-click the folder you want to copy and click Copy Folder name. Click the Gmail Folder in Outlook to copy that folder in that location. You can repeat the steps as needed for other folders.
That's it!
Step 1: Enable IMAP in your Gmail account and then
configure Outlook (or Outlook Express or Windows Live Mail) to sync
with your Gmail address via IMAP. Read this guide.
Step 2: Import your Outlook PST file into a Personal folder that is different from your default Gmail Inbox.
To import, click File -> Import And Export -> Import from another program or file. -> Next -> Personal Folder File (.pst)
-> Next.
Select the PST file that contains your email, then pick the email folders that you want to import in Outlook and click Finish.
Step 3: Select the Personal folders that you want to backup online and copy them your Gmail Folder in Outlook.
In the Folder List, right-click the folder you want to copy and click Copy Folder name. Click the Gmail Folder in Outlook to copy that folder in that location. You can repeat the steps as needed for other folders.
That's it!
Saturday, May 2, 2009
How to reset my Joomla administrator password?
Joomla's admin username can be easily changed with a simple MySQL query. The most convenient way to manage the database is through the phpMyAdmin tool. Go to your cPanel and click on phpMyAdmin in the Databases box. (If you are not using cPanel or do not have phpMyAdmin, you can run the query directly for Joomla's database.)
Once in the phpMyAdmin select the Joomla database from the drop-down menu at left. The page will refresh and the database's tables will be displayed on it. Open the SQL tab (look at the top navigation bar).
In the text field write the following SQL query:
UPDATE `jos_users` SET `password` = MD5( 'new_password' ) WHERE `jos_users`.`username` = "admin" ;
"new_password" - replace this with the new password you wish to use.
"admin" - replace this if your admin username is different.
Once you are ready, click on the GO button to submit the query. If everything goes fine without errors, you should be able to login to Joomla with the new password.
Note: These instructions are valid both for Joomla 1.5 and Joomla 1.0.*.
If you have problems resetting the password yourself, ask your host for assistance. SiteGround provides the best Joomla hosting and such requests are handled with ease.
Once in the phpMyAdmin select the Joomla database from the drop-down menu at left. The page will refresh and the database's tables will be displayed on it. Open the SQL tab (look at the top navigation bar).
In the text field write the following SQL query:
UPDATE `jos_users` SET `password` = MD5( 'new_password' ) WHERE `jos_users`.`username` = "admin" ;
"new_password" - replace this with the new password you wish to use.
"admin" - replace this if your admin username is different.
Once you are ready, click on the GO button to submit the query. If everything goes fine without errors, you should be able to login to Joomla with the new password.
Note: These instructions are valid both for Joomla 1.5 and Joomla 1.0.*.
If you have problems resetting the password yourself, ask your host for assistance. SiteGround provides the best Joomla hosting and such requests are handled with ease.
Saturday, April 11, 2009
lamp/bind/ntp
Install CentOS 5.2 as a server (LAMP/Bind/ntp)
Posted by aristomagnus on Oct 28, 2008 in Featured, HowTo - Linux • 8 comments
Partition:
/dev/sda1 => ext3 -> /boot -> 128MB
/dev/sda2 => ext3 -> / -> 32768MB
/dev/sda3 => swap -> 2048MB
/dev/sda4 => ext3 -> /tmp -> Space left.
Disable IPv6 support if not needed.
-PACKAGE CONFIGURATION:
* Choose SERVER Templates.
* In the bottom, check CUSTOMIZE NOW.
-PACKAGES CUSTOMIZATION:
* In DEVELOPMENT: add DEVELOPMENT LIBRARIES, DEVELOPMENT TOOLS, LEGACY SOFTWARE DEVELOPMENT.
* In SERVER: uncheck everything (remove all packages).
* In BASE SYSTEM: add LEGACY SOFTWARE SUPPORT.
reboot
Edit /etc/selinux/config
Change the line:
SELINUX=enforcing
to
SELINUX=disabled
OR
system-config-securitylevel
Disable Security Level and SeLinux disabled
save and reboot
yum -y update
reboot
Disable service: ip6tables iptables bluetooth
chkconfig –levels 0123456 ip6tables off
chkconfig –levels 0123456 iptables off
chkconfig –levels 0123456 bluetooth off
To install a DNS server
yum -y install bind-chroot
To install MySQL server
yum -y install mysql mysql-devel mysql-server
To install php and perl:
yum -y install php php-devel php-gd php-imap php-ldap php-mysql php-odbc php-pear php-xml php-xmlrpc curl curl-devel perl-libwww-perl ImageMagick libxml2 libxml2-devel perl
Configure BIND9 (chrooted DNS Server)
BIND will run in a chroot jail under /var/named/chroot/var/named/ to allow BIND management via ISPConfig.
chmod 755 /var/named/
chmod 775 /var/named/chroot/
chmod 775 /var/named/chroot/var/
chmod 775 /var/named/chroot/var/named/
chmod 775 /var/named/chroot/var/run/
chmod 777 /var/named/chroot/var/run/named/
cd /var/named/chroot/var/named/
ln -s ../../ chroot
cp /usr/share/doc/bind-9.3.4/sample/var/named/named.local /var/named/chroot/var/named/named.local
cp /usr/share/doc/bind-9.3.4/sample/var/named/named.root /var/named/chroot/var/named/named.root
touch /var/named/chroot/etc/named.conf
Enter chkconfig –levels 235 named on
Configure MySQL
Enter chkconfig –levels 235 mysqld on
Note: Consider reviewing the MySQL Tuning guide and Low memory MySQL / Apache configurations for additional MySQL configuration suggestions.
Configure Apache
Modify the DirectoryIndex directive in your httpd.conf file:
vi /etc/httpd/conf/httpd.conf
Locate the DirectoryIndex for your web root
Modify the line to read as follows:
DirectoryIndex index.html index.htm index.shtml index.cgi index.php index.php3 index.pl
Find the line
Options Indexes FollowSymLinks
Remove Indexes from that line
Options FollowSymLinks
Exit vi
chkconfig –levels 235 httpd on
to start Apache whenever your server boots
Test Your Configuration
BIND
/etc/init.d/named restart
MySQL
/etc/init.d/mysqld start
netstat -tap | grep mysql
- if a line with the word LISTEN displays, MySQL was configured successfully and is now running
mysqladmin -u root password
(where is the unique password for your MySQL root account)
clear history
history -c
Add repository to yum:
Howto Repo: http://wiki.centos.org/AdditionalResources/Repositories
—————
FROM RPMforge: http://wiki.centos.org/AdditionalResources/Repositories/RPMForge
1. CentOS 5
You should make sure that you have Priorities installed.
1.1. Priorities
yum install yum-priorities
i386 http://apt.sw.be/redhat/el5/en/i386/RPMS.dag/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
x86_64 http://apt.sw.be/redhat/el5/en/x86_64/RPMS.dag/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm
(You can find a complete list of rpmforge-release package packages at http://dag.wieers.com/packages/rpmforge-release/ but it is recommended that you use one of the two listed above).
x64:
rpm -ivh http://apt.sw.be/redhat/el5/en/x86_64/RPMS.dag/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm
Test with this command:
yum check-update
yum update
yum -y install phpmyadmin php-mcrypt php-mbstring
vi /usr/share/phpmyadmin/config.inc.php
Fine the line :
$cfg['blowfish_secret'] = ”; /* YOU MUST FILL IN THIS FOR COOKIE
AUTH! */
add a secret in the bracket. save the file.
Now you need to configure the access of phpmyadmin:
vi /etc/httpd/conf.d/phpmyadmin.conf
Order Deny,Allow
#Deny from all
Allow from all
/etc/init.d/httpd restart
Try it: http://ipoftheserver/phpmyadmin
user: root
passwd: your password
Synchronize The System Clock
If you want to have the system clock synchronized with an NTP server do the following:
yum install ntp
chkconfig –levels 235 ntpd on
ntpdate 0.pool.ntp.org
/etc/init.d/ntpd start
Install Webmin
cd /tmp
wget http://prdownloads.sourceforge.net/webadmin/webmin-1.441-1.noarch.rpm
rpm -ivh webmin-1.441-1.noarch.rpm
access webmin:
https://ipoftheserver:10000
Some infos are from: http://wiki.vpslink.com/HOWTO:_CentOS_5_setup_for_LAMP_and_ISPconfig#Step-by-step_Installation_Guide
Some infos are from: http://howtoforge.net/perfect-server-centos-5.2-x86_64
Posted by aristomagnus on Oct 28, 2008 in Featured, HowTo - Linux • 8 comments
Partition:
/dev/sda1 => ext3 -> /boot -> 128MB
/dev/sda2 => ext3 -> / -> 32768MB
/dev/sda3 => swap -> 2048MB
/dev/sda4 => ext3 -> /tmp -> Space left.
Disable IPv6 support if not needed.
-PACKAGE CONFIGURATION:
* Choose SERVER Templates.
* In the bottom, check CUSTOMIZE NOW.
-PACKAGES CUSTOMIZATION:
* In DEVELOPMENT: add DEVELOPMENT LIBRARIES, DEVELOPMENT TOOLS, LEGACY SOFTWARE DEVELOPMENT.
* In SERVER: uncheck everything (remove all packages).
* In BASE SYSTEM: add LEGACY SOFTWARE SUPPORT.
reboot
Edit /etc/selinux/config
Change the line:
SELINUX=enforcing
to
SELINUX=disabled
OR
system-config-securitylevel
Disable Security Level and SeLinux disabled
save and reboot
yum -y update
reboot
Disable service: ip6tables iptables bluetooth
chkconfig –levels 0123456 ip6tables off
chkconfig –levels 0123456 iptables off
chkconfig –levels 0123456 bluetooth off
To install a DNS server
yum -y install bind-chroot
To install MySQL server
yum -y install mysql mysql-devel mysql-server
To install php and perl:
yum -y install php php-devel php-gd php-imap php-ldap php-mysql php-odbc php-pear php-xml php-xmlrpc curl curl-devel perl-libwww-perl ImageMagick libxml2 libxml2-devel perl
Configure BIND9 (chrooted DNS Server)
BIND will run in a chroot jail under /var/named/chroot/var/named/ to allow BIND management via ISPConfig.
chmod 755 /var/named/
chmod 775 /var/named/chroot/
chmod 775 /var/named/chroot/var/
chmod 775 /var/named/chroot/var/named/
chmod 775 /var/named/chroot/var/run/
chmod 777 /var/named/chroot/var/run/named/
cd /var/named/chroot/var/named/
ln -s ../../ chroot
cp /usr/share/doc/bind-9.3.4/sample/var/named/named.local /var/named/chroot/var/named/named.local
cp /usr/share/doc/bind-9.3.4/sample/var/named/named.root /var/named/chroot/var/named/named.root
touch /var/named/chroot/etc/named.conf
Enter chkconfig –levels 235 named on
Configure MySQL
Enter chkconfig –levels 235 mysqld on
Note: Consider reviewing the MySQL Tuning guide and Low memory MySQL / Apache configurations for additional MySQL configuration suggestions.
Configure Apache
Modify the DirectoryIndex directive in your httpd.conf file:
vi /etc/httpd/conf/httpd.conf
Locate the DirectoryIndex for your web root
Modify the line to read as follows:
DirectoryIndex index.html index.htm index.shtml index.cgi index.php index.php3 index.pl
Find the line
Options Indexes FollowSymLinks
Remove Indexes from that line
Options FollowSymLinks
Exit vi
chkconfig –levels 235 httpd on
to start Apache whenever your server boots
Test Your Configuration
BIND
/etc/init.d/named restart
MySQL
/etc/init.d/mysqld start
netstat -tap | grep mysql
- if a line with the word LISTEN displays, MySQL was configured successfully and is now running
mysqladmin -u root password
(where
clear history
history -c
Add repository to yum:
Howto Repo: http://wiki.centos.org/AdditionalResources/Repositories
—————
FROM RPMforge: http://wiki.centos.org/AdditionalResources/Repositories/RPMForge
1. CentOS 5
You should make sure that you have Priorities installed.
1.1. Priorities
yum install yum-priorities
i386 http://apt.sw.be/redhat/el5/en/i386/RPMS.dag/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
x86_64 http://apt.sw.be/redhat/el5/en/x86_64/RPMS.dag/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm
(You can find a complete list of rpmforge-release package packages at http://dag.wieers.com/packages/rpmforge-release/ but it is recommended that you use one of the two listed above).
x64:
rpm -ivh http://apt.sw.be/redhat/el5/en/x86_64/RPMS.dag/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm
Test with this command:
yum check-update
yum update
yum -y install phpmyadmin php-mcrypt php-mbstring
vi /usr/share/phpmyadmin/config.inc.php
Fine the line :
$cfg['blowfish_secret'] = ”; /* YOU MUST FILL IN THIS FOR COOKIE
AUTH! */
add a secret in the bracket. save the file.
Now you need to configure the access of phpmyadmin:
vi /etc/httpd/conf.d/phpmyadmin.conf
Order Deny,Allow
#Deny from all
Allow from all
/etc/init.d/httpd restart
Try it: http://ipoftheserver/phpmyadmin
user: root
passwd: your password
Synchronize The System Clock
If you want to have the system clock synchronized with an NTP server do the following:
yum install ntp
chkconfig –levels 235 ntpd on
ntpdate 0.pool.ntp.org
/etc/init.d/ntpd start
Install Webmin
cd /tmp
wget http://prdownloads.sourceforge.net/webadmin/webmin-1.441-1.noarch.rpm
rpm -ivh webmin-1.441-1.noarch.rpm
access webmin:
https://ipoftheserver:10000
Some infos are from: http://wiki.vpslink.com/HOWTO:_CentOS_5_setup_for_LAMP_and_ISPconfig#Step-by-step_Installation_Guide
Some infos are from: http://howtoforge.net/perfect-server-centos-5.2-x86_64
static ip in linux
vi /etc/sysconfig/network-scripts/ifcfg-eth0
Code:
DEVICE=eth0
BOOTPROTO=static
HWADDR=00:11:85:BC:7D:5F (YOUR NIC MAC ADDRESS)
IPADDR=111.111.111.111
NETMASK=255.255.255.0
ONBOOT=yes
TYPE=Ethernet
vi /etc/sysconfig/network
Code:
NETWORKING=yes
HOSTNAME=YOURDOMAIN.com (locoalhost.localdomain)
GATEWAY=111.111.111.111
Code:
DEVICE=eth0
BOOTPROTO=static
HWADDR=00:11:85:BC:7D:5F (YOUR NIC MAC ADDRESS)
IPADDR=111.111.111.111
NETMASK=255.255.255.0
ONBOOT=yes
TYPE=Ethernet
vi /etc/sysconfig/network
Code:
NETWORKING=yes
HOSTNAME=YOURDOMAIN.com (locoalhost.localdomain)
GATEWAY=111.111.111.111
centos- yum
Installing Apache, PHP, and MySQL on Fedora Core
This will install the basic components for a dynmaic, database-driven web site. We use yum to handle dependencies and gather all of the required packages.
1. Install Apache (httpd), PHP, MySQL (server and client), and the component that allows php to talk to mysql.
yum -y install httpd php mysql mysql-server php-mysql
2. Configure the new services to start automatically
/sbin/chkconfig httpd on
/sbin/chkconfig --add mysqld [this is not required with FC4 and above]
/sbin/chkconfig mysqld on
/sbin/service httpd start
/sbin/service mysqld start
3. IMPORTANT! Set up the mysql database root password. Without a password, ANY user on the box can login to mysql as database root. The mysql root account is a separate password from the machine root account.
mysqladmin -u root password 'new-password' [quotes are required]
4. Make additional security-related changes to mysql.
mysql -u root -p
mysql> DROP DATABASE test; [removes the test database]
mysql> DELETE FROM mysql.user WHERE user = ''; [Removes anonymous access]
mysql> FLUSH PRIVILEGES;
5. Following the above steps, the document root for Apache is /var/www/html/
Create a test PHP script (such as phpinfo.php) and place it in the document root. A useful test script sample:
phpinfo();
?>
6. Create a database and database user for your data. You will use this database and user name in your database connection string. The GRANT statement actually creates a new MySQL user account.
mysql> CREATE DATABASE web_db;
mysql> GRANT ALL PRIVILEGES ON web_db.* TO 'web_user'@'localhost' IDENTIFIED BY 'thepassword';
This will install the basic components for a dynmaic, database-driven web site. We use yum to handle dependencies and gather all of the required packages.
1. Install Apache (httpd), PHP, MySQL (server and client), and the component that allows php to talk to mysql.
yum -y install httpd php mysql mysql-server php-mysql
2. Configure the new services to start automatically
/sbin/chkconfig httpd on
/sbin/chkconfig --add mysqld [this is not required with FC4 and above]
/sbin/chkconfig mysqld on
/sbin/service httpd start
/sbin/service mysqld start
3. IMPORTANT! Set up the mysql database root password. Without a password, ANY user on the box can login to mysql as database root. The mysql root account is a separate password from the machine root account.
mysqladmin -u root password 'new-password' [quotes are required]
4. Make additional security-related changes to mysql.
mysql -u root -p
mysql> DROP DATABASE test; [removes the test database]
mysql> DELETE FROM mysql.user WHERE user = ''; [Removes anonymous access]
mysql> FLUSH PRIVILEGES;
5. Following the above steps, the document root for Apache is /var/www/html/
Create a test PHP script (such as phpinfo.php) and place it in the document root. A useful test script sample:
phpinfo();
?>
6. Create a database and database user for your data. You will use this database and user name in your database connection string. The GRANT statement actually creates a new MySQL user account.
mysql> CREATE DATABASE web_db;
mysql> GRANT ALL PRIVILEGES ON web_db.* TO 'web_user'@'localhost' IDENTIFIED BY 'thepassword';
Wednesday, February 25, 2009
shell script
How to write a shell script
Introduction
A shell is a command line interpretor. It takes commands and executes them. As such, it implements a programming language. The Bourne shell is used to create shell scripts -- ie. programs that are interpreted/executed by the shell. You can write shell scripts with the C-shell; however, this is not covered here.
Creating a Script
Suppose you often type the command
find . -name file -print
and you'd rather type a simple command, say
sfind file
Create a shell script
% cd ~/bin
% emacs sfind
% page sfind
find . -name $1 -print
% chmod a+x sfind
% rehash
% cd /usr/local/bin
% sfind tcsh
./shells/tcsh
Observations
This quick example is far from adequate but some observations:
1. Shell scripts are simple text files created with an editor.
2. Shell scripts are marked as executeable
%chmod a+x sfind
3. Should be located in your search path and ~/bin should be in your search path.
4. You likely need to rehash if you're a Csh (tcsh) user (but not again when you login).
5. Arguments are passed from the command line and referenced. For example, as $1.
#!/bin/sh
All Bourne Shell scripts should begin with the sequence
#!/bin/sh
From the man page for exec(2):
"On the first line of an interpreter script, following the "#!", is the name of a program which should be used to interpret the contents of the file. For instance, if the first line contains "#! /bin/sh", then the con- tents of the file are executed as a shell script."
You can get away without this, but you shouldn't. All good scripts state the interpretor explicitly. Long ago there was just one (the Bourne Shell) but these days there are many interpretors -- Csh, Ksh, Bash, and others.
Comments
Comments are any text beginning with the pound (#) sign. A comment can start anywhere on a line and continue until the end of the line.
Search Path
All shell scripts should include a search path specifica- tion:
PATH=/usr/ucb:/usr/bin:/bin; export PATH
A PATH specification is recommended -- often times a script will fail for some people because they have a different or incomplete search path.
The Bourne Shell does not export environment variables to children unless explicitly instructed to do so by using the export command.
Argument Checking
A good shell script should verify that the arguments sup- plied (if any) are correct.
if [ $# -ne 3 ]; then
echo 1>&2 Usage: $0 19 Oct 91
exit 127
fi
This script requires three arguments and gripes accordingly.
Exit status
All Unix utilities should return an exit status.
# is the year out of range for me?
if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of range
exit 127
fi
etc...
# All done, exit ok
exit 0
A non-zero exit status indicates an error condition of some sort while a zero exit status indicates things worked as expected.
On BSD systems there's been an attempt to categorize some of the more common exit status codes. See /usr/include/sysexits.h.
Using exit status
Exit codes are important for those who use your code. Many constructs test on the exit status of a command.
The conditional construct is:
if command; then
command
fi
For example,
if tty -s; then
echo Enter text end with \^D
fi
Your code should be written with the expectation that others will use it. Making sure you return a meaningful exit status will help.
Stdin, Stdout, Stderr
Standard input, output, and error are file descriptors 0, 1, and 2. Each has a particular role and should be used accordingly:
# is the year out of range for me?
if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of my range
exit 127
fi
etc...
# ok, you have the number of days since Jan 1, ...
case `expr $days % 7` in
0)
echo Mon;;
1)
echo Tue;;
etc...
Error messages should appear on stderr not on stdout! Output should appear on stdout. As for input/output dialogue:
# give the fellow a chance to quit
if tty -s ; then
echo This will remove all files in $* since ...
echo $n Ok to procede? $c; read ans
case "$ans" in
n*|N*)
echo File purge abandoned;
exit 0 ;;
esac
RM="rm -rfi"
else
RM="rm -rf"
fi
Note: this code behaves differently if there's a user to communicate with (ie. if the standard input is a tty rather than a pipe, or file, or etc. See tty(1)).
Language Constructs
For loop iteration
Substitute values for variable and perform task:
for variable in word ...
do
command
done
For example:
for i in `cat $LOGS`
do
mv $i $i.$TODAY
cp /dev/null $i
chmod 664 $i
done
Alternatively you may see:
for variable in word ...; do command; done
* Case
Switch to statements depending on pattern match
case word in
[ pattern [ | pattern ... ] )
command ;; ] ...
esac
For example:
case "$year" in
[0-9][0-9])
year=19${year}
years=`expr $year - 1901`
;;
[0-9][0-9][0-9][0-9])
years=`expr $year - 1901`
;;
*)
echo 1>&2 Year \"$year\" out of range ...
exit 127
;;
esac
* Conditional Execution
Test exit status of command and branch
if command
then
command
[ else
command ]
fi
For example:
if [ $# -ne 3 ]; then
echo 1>&2 Usage: $0 19 Oct 91
exit 127
fi
Alternatively you may see:
if command; then command; [ else command; ] fi
* While/Until Iteration
Repeat task while command returns good exit status.
{while | until} command
do
command
done
For example:
# for each argument mentioned, purge that directory
while [ $# -ge 1 ]; do
_purge $1
shift
done
Alternatively you may see:
while command; do command; done
* Variables
Variables are sequences of letters, digits, or underscores beginning with a letter or underscore. To get the contents of a variable you must prepend the name with a $.
Numeric variables (eg. like $1, etc.) are positional vari- ables for argument communication.
o Variable Assignment
Assign a value to a variable by variable=value. For example:
PATH=/usr/ucb:/usr/bin:/bin; export PATH
or
TODAY=`(set \`date\`; echo $1)`
o Exporting Variables
Variables are not exported to children unless explicitly marked.
# We MUST have a DISPLAY environment variable
if [ "$DISPLAY" = "" ]; then
if tty -s ; then
echo "DISPLAY (`hostname`:0.0)? \c";
read DISPLAY
fi
if [ "$DISPLAY" = "" ]; then
DISPLAY=`hostname`:0.0
fi
export DISPLAY
fi
Likewise, for variables like the PRINTER which you want hon- ored by lpr(1). From a user's .profile:
PRINTER=PostScript; export PRINTER
Note: that the Cshell exports all environment variables.
o Referencing Variables
Use $variable (or, if necessary, ${variable}) to reference the value.
# Most user's have a /bin of their own
if [ "$USER" != "root" ]; then
PATH=$HOME/bin:$PATH
else
PATH=/etc:/usr/etc:$PATH
fi
The braces are required for concatenation constructs.
$p_01
The value of the variable "p_01".
${p}_01
The value of the variable "p" with "_01" pasted onto the end.
o Conditional Reference
${variable-word}
If the variable has been set, use it's value, else use word.
POSTSCRIPT=${POSTSCRIPT-PostScript};
export POSTSCRIPT
${variable:-word}
If the variable has been set and is not null, use it's value, else use word.
These are useful constructions for honoring the user envi- ronment. Ie. the user of the script can override variable assignments. Cf. programs like lpr(1) honor the PRINTER environment variable, you can do the same trick with your shell scripts.
${variable:?word}
If variable is set use it's value, else print out word and exit. Useful for bailing out.
o Arguments
Command line arguments to shell scripts are positional vari- ables:
$0, $1, ...
The command and arguments. With $0 the command and the rest the arguments.
$#
The number of arguments.
$*, $@
All the arguments as a blank separated string. Watch out for "$*" vs. "$@".
And, some commands:
shift
Shift the postional variables down one and decrement number of arguments.
set arg arg ...
Set the positional variables to the argument list.
Command line parsing uses shift:
# parse argument list
while [ $# -ge 1 ]; do
case $1 in
process arguments...
esac
shift
done
A use of the set command:
# figure out what day it is
TODAY=`(set \`date\`; echo $1)`
cd $SPOOL
for i in `cat $LOGS`
do
mv $i $i.$TODAY
cp /dev/null $i
chmod 664 $i
done
o Special Variables
$$
Current process id. This is very useful for constructing temporary files.
tmp=/tmp/cal0$$
trap "rm -f $tmp /tmp/cal1$$ /tmp/cal2$$"
trap exit 1 2 13 15
/usr/lib/calprog >$tmp
$?
The exit status of the last command.
$command
# Run target file if no errors and ...
if [ $? -eq 0 ]
then
etc...
fi
* Quotes/Special Characters
Special characters to terminate words:
; & ( ) | ^ < > new-line space tab
These are for command sequences, background jobs, etc. To quote any of these use a backslash (\) or bracket with quote marks ("" or '').
Single Quotes
Within single quotes all characters are quoted -- including the backslash. The result is one word.
grep :${gid}: /etc/group | awk -F: '{print $1}'
Double Quotes
Within double quotes you have variable subsitution (ie. the dollar sign is interpreted) but no file name generation (ie. * and ? are quoted). The result is one word.
if [ ! "${parent}" ]; then
parent=${people}/${group}/${user}
fi
Back Quotes
Back quotes mean run the command and substitute the output.
if [ "`echo -n`" = "-n" ]; then
n=""
c="\c"
else
n="-n"
c=""
fi
and
TODAY=`(set \`date\`; echo $1)`
* Functions
Functions are a powerful feature that aren't used often enough. Syntax is
name ()
{
commands
}
For example:
# Purge a directory
_purge()
{
# there had better be a directory
if [ ! -d $1 ]; then
echo $1: No such directory 1>&2
return
fi
etc...
}
Within a function the positional parmeters $0, $1, etc. are the arguments to the function (not the arguments to the script).
Within a function use return instead of exit.
Functions are good for encapsulations. You can pipe, redi- rect input, etc. to functions. For example:
# deal with a file, add people one at a time
do_file()
{
while parse_one
etc...
}
etc...
# take standard input (or a specified file) and do it.
if [ "$1" != "" ]; then
cat $1 | do_file
else
do_file
fi
* Sourcing commands
You can execute shell scripts from within shell scripts. A couple of choices:
sh command
This runs the shell script as a separate shell. For example, on Sun machines in /etc/rc:
sh /etc/rc.local
. command
This runs the shell script from within the current shell script. For example:
# Read in configuration information
. /etc/hostconfig
What are the virtues of each? What's the difference? The second form is useful for configuration files where environment variable are set for the script. For example:
for HOST in $HOSTS; do
# is there a config file for this host?
if [ -r ${BACKUPHOME}/${HOST} ]; then
. ${BACKUPHOME}/${HOST}
fi
etc...
Using configuration files in this manner makes it possible to write scripts that are automatically tailored for differ- ent situations.
Some Tricks
* Test
The most powerful command is test(1).
if test expression; then
etc...
and (note the matching bracket argument)
if [ expression ]; then
etc...
On System V machines this is a builtin (check out the com- mand /bin/test).
On BSD systems (like the Suns) compare the command /usr/bin/test with /usr/bin/[.
Useful expressions are:
test { -w, -r, -x, -s, ... } filename
is file writeable, readable, executeable, empty, etc?
test n1 { -eq, -ne, -gt, ... } n2
are numbers equal, not equal, greater than, etc.?
test s1 { =, != } s2
Are strings the same or different?
test cond1 { -o, -a } cond2
Binary or; binary and; use ! for unary negation.
For example
if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of range
exit 127
fi
Learn this command inside out! It does a lot for you.
* String matching
The test command provides limited string matching tests. A more powerful trick is to match strings with the case switch.
# parse argument list
while [ $# -ge 1 ]; do
case $1 in
-c*) rate=`echo $1 | cut -c3-`;;
-c) shift; rate=$1 ;;
-p*) prefix=`echo $1 | cut -c3-`;;
-p) shift; prefix=$1 ;;
-*) echo $Usage; exit 1 ;;
*) disks=$*; break ;;
esac
shift
done
Of course getopt would work much better.
* SysV vs BSD echo
On BSD systems to get a prompt you'd say:
echo -n Ok to procede?; read ans
On SysV systems you'd say:
echo Ok to procede? \c; read ans
In an effort to produce portable code we've been using:
# figure out what kind of echo to use
if [ "`echo -n`" = "-n" ]; then
n=""; c="\c"
else
n="-n"; c=""
fi
etc...
echo $n Ok to procede? $c; read ans
* Is there a person?
The Unix tradition is that programs should execute as qui- etly as possible. Especially for pipelines, cron jobs, etc.
User prompts aren't required if there's no user.
# If there's a person out there, prod him a bit.
if tty -s; then
echo Enter text end with \^D
fi
The tradition also extends to output.
# If the output is to a terminal, be verbose
if tty -s <&1; then
verbose=true
else
verbose=false
fi
Beware: just because stdin is a tty that doesn't mean that stdout is too. User prompts should be directed to the user terminal.
# If there's a person out there, prod him a bit.
if tty -s; then
echo Enter text end with \^D >&0
fi
Have you ever had a program stop waiting for keyboard input when the output is directed elsewhere?
* Creating Input
We're familiar with redirecting input. For example:
# take standard input (or a specified file) and do it.
if [ "$1" != "" ]; then
cat $1 | do_file
else
do_file
fi
alternatively, redirection from a file:
# take standard input (or a specified file) and do it.
if [ "$1" != "" ]; then
do_file < $1
else
do_file
fi
You can also construct files on the fly.
rmail bsmtp <<$1@newshost.uwo.ca>
rcpt to:
data
from: <$1@newshost.uwo.ca>
to:
Subject: Signon $2
subscribe $2 Usenet Feeder at UWO
.
quit
EOF
Note: that variables are expanded in the input.
* String Manipulations
One of the more common things you'll need to do is parse strings. Some tricks
TIME=`date | cut -c12-19`
TIME=`date | sed 's/.* .* .* \(.*\) .* .*/\1/'`
TIME=`date | awk '{print $4}'`
TIME=`set \`date\`; echo $4`
TIME=`date | (read u v w x y z; echo $x)`
With some care, redefining the input field separators can help.
#!/bin/sh
# convert IP number to in-addr.arpa name
name()
{ set `IFS=".";echo $1`
echo $4.$3.$2.$1.in-addr.arpa
}
if [ $# -ne 1 ]; then
echo 1>&2 Usage: bynum IP-address
exit 127
fi
add=`name $1`
nslookup < < EOF | grep "$add" | sed 's/.*= //'
set type=any
$add
EOF
* Debugging
The shell has a number of flags that make debugging easier:
sh -n command
Read the shell script but don't execute the commands. IE. check syntax.
sh -x command
Display commands and arguments as they're executed. In a lot of my shell scripts you'll see
# Uncomment the next line for testing
# set -x
Based on An Introduction to Shell Programing by:
Reg Quinton
Computing and Communications Services
The University of Western Ontario
London, Ontario N6A 5B7
Canada
Press here to return to the General Unix Software Menu.
Introduction
A shell is a command line interpretor. It takes commands and executes them. As such, it implements a programming language. The Bourne shell is used to create shell scripts -- ie. programs that are interpreted/executed by the shell. You can write shell scripts with the C-shell; however, this is not covered here.
Creating a Script
Suppose you often type the command
find . -name file -print
and you'd rather type a simple command, say
sfind file
Create a shell script
% cd ~/bin
% emacs sfind
% page sfind
find . -name $1 -print
% chmod a+x sfind
% rehash
% cd /usr/local/bin
% sfind tcsh
./shells/tcsh
Observations
This quick example is far from adequate but some observations:
1. Shell scripts are simple text files created with an editor.
2. Shell scripts are marked as executeable
%chmod a+x sfind
3. Should be located in your search path and ~/bin should be in your search path.
4. You likely need to rehash if you're a Csh (tcsh) user (but not again when you login).
5. Arguments are passed from the command line and referenced. For example, as $1.
#!/bin/sh
All Bourne Shell scripts should begin with the sequence
#!/bin/sh
From the man page for exec(2):
"On the first line of an interpreter script, following the "#!", is the name of a program which should be used to interpret the contents of the file. For instance, if the first line contains "#! /bin/sh", then the con- tents of the file are executed as a shell script."
You can get away without this, but you shouldn't. All good scripts state the interpretor explicitly. Long ago there was just one (the Bourne Shell) but these days there are many interpretors -- Csh, Ksh, Bash, and others.
Comments
Comments are any text beginning with the pound (#) sign. A comment can start anywhere on a line and continue until the end of the line.
Search Path
All shell scripts should include a search path specifica- tion:
PATH=/usr/ucb:/usr/bin:/bin; export PATH
A PATH specification is recommended -- often times a script will fail for some people because they have a different or incomplete search path.
The Bourne Shell does not export environment variables to children unless explicitly instructed to do so by using the export command.
Argument Checking
A good shell script should verify that the arguments sup- plied (if any) are correct.
if [ $# -ne 3 ]; then
echo 1>&2 Usage: $0 19 Oct 91
exit 127
fi
This script requires three arguments and gripes accordingly.
Exit status
All Unix utilities should return an exit status.
# is the year out of range for me?
if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of range
exit 127
fi
etc...
# All done, exit ok
exit 0
A non-zero exit status indicates an error condition of some sort while a zero exit status indicates things worked as expected.
On BSD systems there's been an attempt to categorize some of the more common exit status codes. See /usr/include/sysexits.h.
Using exit status
Exit codes are important for those who use your code. Many constructs test on the exit status of a command.
The conditional construct is:
if command; then
command
fi
For example,
if tty -s; then
echo Enter text end with \^D
fi
Your code should be written with the expectation that others will use it. Making sure you return a meaningful exit status will help.
Stdin, Stdout, Stderr
Standard input, output, and error are file descriptors 0, 1, and 2. Each has a particular role and should be used accordingly:
# is the year out of range for me?
if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of my range
exit 127
fi
etc...
# ok, you have the number of days since Jan 1, ...
case `expr $days % 7` in
0)
echo Mon;;
1)
echo Tue;;
etc...
Error messages should appear on stderr not on stdout! Output should appear on stdout. As for input/output dialogue:
# give the fellow a chance to quit
if tty -s ; then
echo This will remove all files in $* since ...
echo $n Ok to procede? $c; read ans
case "$ans" in
n*|N*)
echo File purge abandoned;
exit 0 ;;
esac
RM="rm -rfi"
else
RM="rm -rf"
fi
Note: this code behaves differently if there's a user to communicate with (ie. if the standard input is a tty rather than a pipe, or file, or etc. See tty(1)).
Language Constructs
For loop iteration
Substitute values for variable and perform task:
for variable in word ...
do
command
done
For example:
for i in `cat $LOGS`
do
mv $i $i.$TODAY
cp /dev/null $i
chmod 664 $i
done
Alternatively you may see:
for variable in word ...; do command; done
* Case
Switch to statements depending on pattern match
case word in
[ pattern [ | pattern ... ] )
command ;; ] ...
esac
For example:
case "$year" in
[0-9][0-9])
year=19${year}
years=`expr $year - 1901`
;;
[0-9][0-9][0-9][0-9])
years=`expr $year - 1901`
;;
*)
echo 1>&2 Year \"$year\" out of range ...
exit 127
;;
esac
* Conditional Execution
Test exit status of command and branch
if command
then
command
[ else
command ]
fi
For example:
if [ $# -ne 3 ]; then
echo 1>&2 Usage: $0 19 Oct 91
exit 127
fi
Alternatively you may see:
if command; then command; [ else command; ] fi
* While/Until Iteration
Repeat task while command returns good exit status.
{while | until} command
do
command
done
For example:
# for each argument mentioned, purge that directory
while [ $# -ge 1 ]; do
_purge $1
shift
done
Alternatively you may see:
while command; do command; done
* Variables
Variables are sequences of letters, digits, or underscores beginning with a letter or underscore. To get the contents of a variable you must prepend the name with a $.
Numeric variables (eg. like $1, etc.) are positional vari- ables for argument communication.
o Variable Assignment
Assign a value to a variable by variable=value. For example:
PATH=/usr/ucb:/usr/bin:/bin; export PATH
or
TODAY=`(set \`date\`; echo $1)`
o Exporting Variables
Variables are not exported to children unless explicitly marked.
# We MUST have a DISPLAY environment variable
if [ "$DISPLAY" = "" ]; then
if tty -s ; then
echo "DISPLAY (`hostname`:0.0)? \c";
read DISPLAY
fi
if [ "$DISPLAY" = "" ]; then
DISPLAY=`hostname`:0.0
fi
export DISPLAY
fi
Likewise, for variables like the PRINTER which you want hon- ored by lpr(1). From a user's .profile:
PRINTER=PostScript; export PRINTER
Note: that the Cshell exports all environment variables.
o Referencing Variables
Use $variable (or, if necessary, ${variable}) to reference the value.
# Most user's have a /bin of their own
if [ "$USER" != "root" ]; then
PATH=$HOME/bin:$PATH
else
PATH=/etc:/usr/etc:$PATH
fi
The braces are required for concatenation constructs.
$p_01
The value of the variable "p_01".
${p}_01
The value of the variable "p" with "_01" pasted onto the end.
o Conditional Reference
${variable-word}
If the variable has been set, use it's value, else use word.
POSTSCRIPT=${POSTSCRIPT-PostScript};
export POSTSCRIPT
${variable:-word}
If the variable has been set and is not null, use it's value, else use word.
These are useful constructions for honoring the user envi- ronment. Ie. the user of the script can override variable assignments. Cf. programs like lpr(1) honor the PRINTER environment variable, you can do the same trick with your shell scripts.
${variable:?word}
If variable is set use it's value, else print out word and exit. Useful for bailing out.
o Arguments
Command line arguments to shell scripts are positional vari- ables:
$0, $1, ...
The command and arguments. With $0 the command and the rest the arguments.
$#
The number of arguments.
$*, $@
All the arguments as a blank separated string. Watch out for "$*" vs. "$@".
And, some commands:
shift
Shift the postional variables down one and decrement number of arguments.
set arg arg ...
Set the positional variables to the argument list.
Command line parsing uses shift:
# parse argument list
while [ $# -ge 1 ]; do
case $1 in
process arguments...
esac
shift
done
A use of the set command:
# figure out what day it is
TODAY=`(set \`date\`; echo $1)`
cd $SPOOL
for i in `cat $LOGS`
do
mv $i $i.$TODAY
cp /dev/null $i
chmod 664 $i
done
o Special Variables
$$
Current process id. This is very useful for constructing temporary files.
tmp=/tmp/cal0$$
trap "rm -f $tmp /tmp/cal1$$ /tmp/cal2$$"
trap exit 1 2 13 15
/usr/lib/calprog >$tmp
$?
The exit status of the last command.
$command
# Run target file if no errors and ...
if [ $? -eq 0 ]
then
etc...
fi
* Quotes/Special Characters
Special characters to terminate words:
; & ( ) | ^ < > new-line space tab
These are for command sequences, background jobs, etc. To quote any of these use a backslash (\) or bracket with quote marks ("" or '').
Single Quotes
Within single quotes all characters are quoted -- including the backslash. The result is one word.
grep :${gid}: /etc/group | awk -F: '{print $1}'
Double Quotes
Within double quotes you have variable subsitution (ie. the dollar sign is interpreted) but no file name generation (ie. * and ? are quoted). The result is one word.
if [ ! "${parent}" ]; then
parent=${people}/${group}/${user}
fi
Back Quotes
Back quotes mean run the command and substitute the output.
if [ "`echo -n`" = "-n" ]; then
n=""
c="\c"
else
n="-n"
c=""
fi
and
TODAY=`(set \`date\`; echo $1)`
* Functions
Functions are a powerful feature that aren't used often enough. Syntax is
name ()
{
commands
}
For example:
# Purge a directory
_purge()
{
# there had better be a directory
if [ ! -d $1 ]; then
echo $1: No such directory 1>&2
return
fi
etc...
}
Within a function the positional parmeters $0, $1, etc. are the arguments to the function (not the arguments to the script).
Within a function use return instead of exit.
Functions are good for encapsulations. You can pipe, redi- rect input, etc. to functions. For example:
# deal with a file, add people one at a time
do_file()
{
while parse_one
etc...
}
etc...
# take standard input (or a specified file) and do it.
if [ "$1" != "" ]; then
cat $1 | do_file
else
do_file
fi
* Sourcing commands
You can execute shell scripts from within shell scripts. A couple of choices:
sh command
This runs the shell script as a separate shell. For example, on Sun machines in /etc/rc:
sh /etc/rc.local
. command
This runs the shell script from within the current shell script. For example:
# Read in configuration information
. /etc/hostconfig
What are the virtues of each? What's the difference? The second form is useful for configuration files where environment variable are set for the script. For example:
for HOST in $HOSTS; do
# is there a config file for this host?
if [ -r ${BACKUPHOME}/${HOST} ]; then
. ${BACKUPHOME}/${HOST}
fi
etc...
Using configuration files in this manner makes it possible to write scripts that are automatically tailored for differ- ent situations.
Some Tricks
* Test
The most powerful command is test(1).
if test expression; then
etc...
and (note the matching bracket argument)
if [ expression ]; then
etc...
On System V machines this is a builtin (check out the com- mand /bin/test).
On BSD systems (like the Suns) compare the command /usr/bin/test with /usr/bin/[.
Useful expressions are:
test { -w, -r, -x, -s, ... } filename
is file writeable, readable, executeable, empty, etc?
test n1 { -eq, -ne, -gt, ... } n2
are numbers equal, not equal, greater than, etc.?
test s1 { =, != } s2
Are strings the same or different?
test cond1 { -o, -a } cond2
Binary or; binary and; use ! for unary negation.
For example
if [ $year -lt 1901 -o $year -gt 2099 ]; then
echo 1>&2 Year \"$year\" out of range
exit 127
fi
Learn this command inside out! It does a lot for you.
* String matching
The test command provides limited string matching tests. A more powerful trick is to match strings with the case switch.
# parse argument list
while [ $# -ge 1 ]; do
case $1 in
-c*) rate=`echo $1 | cut -c3-`;;
-c) shift; rate=$1 ;;
-p*) prefix=`echo $1 | cut -c3-`;;
-p) shift; prefix=$1 ;;
-*) echo $Usage; exit 1 ;;
*) disks=$*; break ;;
esac
shift
done
Of course getopt would work much better.
* SysV vs BSD echo
On BSD systems to get a prompt you'd say:
echo -n Ok to procede?; read ans
On SysV systems you'd say:
echo Ok to procede? \c; read ans
In an effort to produce portable code we've been using:
# figure out what kind of echo to use
if [ "`echo -n`" = "-n" ]; then
n=""; c="\c"
else
n="-n"; c=""
fi
etc...
echo $n Ok to procede? $c; read ans
* Is there a person?
The Unix tradition is that programs should execute as qui- etly as possible. Especially for pipelines, cron jobs, etc.
User prompts aren't required if there's no user.
# If there's a person out there, prod him a bit.
if tty -s; then
echo Enter text end with \^D
fi
The tradition also extends to output.
# If the output is to a terminal, be verbose
if tty -s <&1; then
verbose=true
else
verbose=false
fi
Beware: just because stdin is a tty that doesn't mean that stdout is too. User prompts should be directed to the user terminal.
# If there's a person out there, prod him a bit.
if tty -s; then
echo Enter text end with \^D >&0
fi
Have you ever had a program stop waiting for keyboard input when the output is directed elsewhere?
* Creating Input
We're familiar with redirecting input. For example:
# take standard input (or a specified file) and do it.
if [ "$1" != "" ]; then
cat $1 | do_file
else
do_file
fi
alternatively, redirection from a file:
# take standard input (or a specified file) and do it.
if [ "$1" != "" ]; then
do_file < $1
else
do_file
fi
You can also construct files on the fly.
rmail bsmtp <<$1@newshost.uwo.ca>
rcpt to:
data
from: <$1@newshost.uwo.ca>
to:
Subject: Signon $2
subscribe $2 Usenet Feeder at UWO
.
quit
EOF
Note: that variables are expanded in the input.
* String Manipulations
One of the more common things you'll need to do is parse strings. Some tricks
TIME=`date | cut -c12-19`
TIME=`date | sed 's/.* .* .* \(.*\) .* .*/\1/'`
TIME=`date | awk '{print $4}'`
TIME=`set \`date\`; echo $4`
TIME=`date | (read u v w x y z; echo $x)`
With some care, redefining the input field separators can help.
#!/bin/sh
# convert IP number to in-addr.arpa name
name()
{ set `IFS=".";echo $1`
echo $4.$3.$2.$1.in-addr.arpa
}
if [ $# -ne 1 ]; then
echo 1>&2 Usage: bynum IP-address
exit 127
fi
add=`name $1`
nslookup < < EOF | grep "$add" | sed 's/.*= //'
set type=any
$add
EOF
* Debugging
The shell has a number of flags that make debugging easier:
sh -n command
Read the shell script but don't execute the commands. IE. check syntax.
sh -x command
Display commands and arguments as they're executed. In a lot of my shell scripts you'll see
# Uncomment the next line for testing
# set -x
Based on An Introduction to Shell Programing by:
Reg Quinton
Computing and Communications Services
The University of Western Ontario
London, Ontario N6A 5B7
Canada
Press here to return to the General Unix Software Menu.
Subscribe to:
Posts (Atom)