Você está na página 1de 85

Programming on the shell

$for file in * >do >if grep -q POSIX $file >then >echo $file >fi >done

Variables
$ salutation=Hello $ echo $salutation Hello $ salutation=Yes Dear $ echo $salutation Yes Dear $ salutation=7+5 $ echo $salutation 7+5 Note->1. how a string must be delimited by quote marks if it contains spaces. 2. In addition,there cant be any spaces on either side of the equals sign.

User Input
$ read salutation Wie gehts? $ echo $salutation Wie gehts?

Playing with variables


myvar=Hi there echo $myvar echo $myvar echo $myvar echo \$myvar echo Enter some text read myvar echo $myvar now equals $myvar

This behaves as follows: $ ./variable Hi there Hi there $myvar $myvar Enter some text Hello World $myvar now equals Hello World

Environmental variables
Environment Variable Description $HOME The home directory of the current user $PATH A colon-separated list of directories to search for commands $IFS An input field separator. $0 The name of the shell script $# The number of parameters passed $$ The process ID of the shell script $1, $2, The parameters given to the script $* A list of all the parameters $@ A subtle variation on $*; it doesnt use the IFS environment variable, so parameters are not run together even if IFS is empty.

salutation=Hello echo $salutation echo The program $0 is now running echo The second parameter was $2 echo The first parameter was $1 echo The parameter list was $* echo The users home directory is $HOME echo Please enter a new greeting read salutation echo $salutation echo The script is now complete

$ ./try_var first bar baz Hello The program ./try_var is now running The second parameter was bar The first parameter was first The parameter list was first bar baz The users home directory is /home/rick Please enter a new greeting Sire Sire The script is now complete $

$ IFS= $ set first bar bam $ echo $@ first bar bam $ echo $* firstbarbam $ unset IFS $ echo $* first bar bam

Condition
Test or [ command $ if test f1.txt then echo exists else echo not fi // if [ f1.txt ]

Condition types
String string1 = string2 string1 != string2 -n string -z string Arithmetic expression1 -eq expression2 expression1 -ne expression2 expression1 -gt expression2 expression1 -ge expression2 expression2 expression1 -lt expression2 T expression1 -le expression2 ! expression File Conditional -d file -f file -g file -r file -s file -u file -w file -x file Comparison Result True if the strings are equal True if the strings are not equal True if the string is not null True if the string is null (an empty string) Comparison Result True if the expressions are equal True if the expressions are not equal True if expression1 is greater than expression2 True if expression1 is greater than or equal to rue if expression1 is less than expression2 True if expression1 is less than or equal to expression2 True if the expression is false, and vice versa Result True if the file is a directory True if the file is a regular file True if set-group-id is set on file True if the file is readable True if the file has nonzero size True if set-user-id is set on file True if the file is writable True if the file is executable

Control Structures
if The if statement is very simple: It tests the result of a command and then conditionally executes a group of statements: if condition then Statements else statements fi

if [ -f /bin/bash ] then echo file /bin/bash exists fi if [ -d /bin/bash ] then echo /bin/bash is a directory else echo /bin/bash is NOT a directory fi

elif
echo Is it morning? Please answer yes or no read timeofday if [ $timeofday = yes + then echo Good morning elif [ $timeofday = no +; then echo Good afternoon else echo Sorry, $timeofday not recognized. Enter yes or no

Problem
Error: [: =: unary operator expected The problem is in the first if clause. When the variable timeofday was tested, it consisted of a blank string. Therefore, the if clause looks like
if * = yes +

which isnt a valid condition. To avoid this, you must use quotes around the variable:
if * $timeofday = yes +

An empty variable then gives the valid test:


if * = yes +

For loop
The syntax is : for variable in values do statements done

Example
for f in bar fudge 43 do echo $f Done That results in the following output: bar fudge 43

While loop
while condition do statements done

Example
echo Enter password read trythis while * $trythis != secret +; do echo Sorry, try again read trythis done An example of the output from this script is as follows: Enter password password Sorry, try again Secret $

Until
until condition do statements done

Example
until who | grep $1 > /dev/null do sleep 60 done # now ring the bell and announce the expected user. echo -e \a echo **** $1 has just logged in ****

While -> loop executes at least once. Until -> if it may not need to execute at all

Case
case variable in pattern [ | pattern] ...) statements;; pattern [ | pattern] ...) statements;; ... esac

read timeofday case $timeofday in yes) echo Good Morning;; no ) echo Good Afternoon;; y ) echo Good Morning;; n ) echo Good Afternoon;; * ) echo Sorry, answer not recognized;; esac

echo Is it morning? Please answer yes or no read timeofday case $timeofday in yes | y | Yes | YES ) echo Good Morning;; n* | N* ) echo Good Afternoon;; * ) echo Sorry, answer not recognized;; esac

echo Is it morning? Please answer yes or no read timeofday case $timeofday in yes | y | Yes | YES ) echo Good Morning echo Up bright and early this morning ;; [nN]*) echo Good Afternoon ;; *) echo Sorry, answer not recognized echo Please answer yes or no ;; esac

Lists
if [ -f this_file ]; then if [ -f that_file ]; then if [ -f the_other_file ]; then echo All files present, and correct fi fi fi

The AND List


statement1 && statement2 && statement3 && ...
touch file_one rm -f file_two if [ -f file_one + && echo hello && * -f file_two + && echo there then echo in if else echo in else fi

The OR List
statement1 || statement2 || statement3 || ...
rm -f file_one if [ -f file_one + || echo hello || echo there then echo in if else echo in else fi This results in the following output: hello in if

Functions
function_name () { statements }
fun() { echo Function first is executing } echo script starting fun echo script ended

fun() { echo Function fun is executing } echo script starting fun echo script ended Running the script will output the following: script starting Function fun is executing script ending

Break command
for file in fred* do if [ -d $file +; then break; fi done echo first directory starting fred was $file rm -rf fred*

The : Command
The colon command is a null command. rm -f fred if [ -f fred ]; then : else echo file fred did not exist fi

Suppressing new line character


echo -n string to output echo -e string to output\c echo -e string to output\t

expr
x=`expr $x + 1` x=$(expr $x + 1)

Why not to make a system call?


Theres a performance penalty in making a system call. System calls are therefore expensive compared to function calls because Linux has to switch from running your program code to executing its own kernel code and back again. Its a good idea to keep the number of system calls used in a program to a minimum and get each call to do as much work as possible, for example, by reading and writing large amounts of data rather than a single character at a time. The hardware has limitations that can impose restrictions on the size of data blocks that can be read or written by the low-level system call at any one time. For example, tape drives often have a block size, say 10k, to which they can write. So, if you attempt to write an amount that is not an exact multiple of 10k, the drive will still advance the tape to the next 10k block, leaving gaps on the tape.

write
#include <unistd.h> size_t write(int fildes, const void *buf, size_t nbytes); #include <unistd.h> #include <stdlib.h> int main() { if ((write(1, Here is some data\n, 18)) != 18) write(2, A write error has occurred on file descriptor 1\n,46); exit(0); }

read
#include <unistd.h> size_t read(int fildes, void *buf, size_t nbytes); #include <unistd.h> #include <stdlib.h> int main() { char buffer[128]; int nread; nread = read(0, buffer, 128); if (nread == -1) write(2, A read error has occurred\n, 26); if ((write(1,buffer,nread)) != nread) write(2, A write error has occurred\n,27); }

open
#include <fcntl.h> int open(const char *path, int flags, ...); int open(const char *path, int oflags, mode_t mode);

O_APPEND: Place written data at the end of the file. O_TRUNC: Set the length of the file to zero, discarding existing contents. O_CREAT: Creates the file, if necessary, with permissions given in mode

S_IRUSR: Read permission, owner S_IWUSR: Write permission, owner S_IXUSR: Execute permission, owner S_IRGRP: Read permission, group S_IWGRP: Write permission, group S_IXGRP: Execute permission, group S_IROTH: Read permission, others S_IWOTH: Write permission, others S_IXOTH: Execute permission, others

open (myfile, O_CREAT, S_IRUSR|S_IXOTH); $ ls -ls myfile -r-------x 1 neil software 0 Sep 22 08:11 myfile*

umask

close
#include <unistd.h> int close(int fildes);

Copy program
First you will need to make a test input file, say 1Mb in size, and name it file.in. Then compile copy_system.c: #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> int main() { char c; int in, out; in = open(file.in, O_RDONLY); out = open(file.out , O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); while(read(in,&c,1) == 1) write(out,&c,1); exit(0); }

$ TIMEFORMAT= time ./copy_system 4.67user 146.90system 2:32.57elapsed 99%CPU ... $ ls -ls file.in file.out 1029 -rw-r---r- 1 neil users 1048576 Sep 17 10:46 file.in 1029 -rw------- 1 neil users 1048576 Sep 17 10:51 file.out

2nd copy program


#include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> int main() { char block[1024]; int in, out; int nread; in = open(file.in, O_RDONLY); out = open(file.out, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); while((nread = read(in,block,sizeof(block))) > 0) write(out,block,nread); }

$ rm file.out $ TIMEFORMAT= time ./copy_block 0.00user 0.02system 0:00.04elapsed 78%CPU

lseek
#include <unistd.h> #include <sys/types.h> off_t lseek(int fildes, off_t offset, int whence);
SEEK_SET: offset is an absolute position SEEK_CUR: offset is relative to the current position SEEK_END: offset is relative to the end of the file

dup and dup2


Duplicating a file descriptor #include <unistd.h> int dup(int fildes); int dup2(int fildes, int fildes2);

fstat
Returns status information about the file associated with an open file descriptor. #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> int fstat(int fildes, struct stat *buf);

st_mode flags
File-type flags
S_IFBLK: Entry is a block special device S_IFDIR: Entry is a directory S_IFCHR: Entry is a character special device S_IFIFO: Entry is a FIFO (named pipe) S_IFREG: Entry is a regular file S_IFLNK: Entry is a symbolic link

Other mode flags include


S_ISUID: Entry has setUID on execution S_ISGID: Entry has setGID on execution

Masks to interpret the st_mode flags include


S_IFMT: File type S_IRWXU: User read/write/execute permissions S_IRWXG: Group read/write/execute permissions S_IRWXO: Others read/write/execute permissions

Program Arguments
int main(int argc, char *argv[])
argc is a count of the program arguments
argv is an array of character strings representing

the arguments themselves.

main() This will still work, because the return type will default to int argc and argv are still there, but if you dont declare them, you cant use them.

$ myprog left right and center the program myprog will start at main with parameters: argc: 4 argv: ,myprog, left, right, and center-

Use of command line arguments


To pass information to programs
$ sort -r file

$ tar cvfB /tmp/file.tar 1024 $ dd if=/dev/fd0 of=/tmp/file.dd bs=18k $ ps ax $ gcc --help $ ls -lstr $ ls -l -s -t -r

#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int arg; for(arg = 0; arg < argc; arg++) { if(argv*arg+*0+ == -) printf(option: %s\n, argv*arg++1); else printf(argument %d: %s\n, arg, argv*arg+); } exit(0); }

$ ./args -i -lr hi there -f fred.c argument 0: ./args option: i option: lr argument 3: hi there option: f argument 5: fred.c

getopt
#include <unistd.h> int getopt(int argc, char *const argv[], const char *optstring); The optstring is simply a list of characters, each representing a single character option. If a character is followed by a colon, it indicates that the option has an associated value

getopt(argc, argv, if:lr );


It allows for simple options -i, -l, -r, and -f, followed by a filename argument

If the option takes a value, that value is pointed to by the external variable optarg. getopt returns -1 when there are no more options to process. A special argument, --, will cause getopt to stop scanning for options. getopt returns ? if there is an unrecognized option, which it stores in the external variable optopt. If an option requires a value (such as -f in our example) and no value is given, getopt normally returns ?. By placing a colon as the first character of the options string, getopt returns : instead of ? when no value is given. The external variable, optind, is set to the index of the next argument to process. getopt uses it to remember how far its got. When all the option arguments have been processed , optind indicates where the remaining arguments can be found at the end of argv array.

#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int opt; while((opt = getopt(argc, argv, :if:lr)) != -1) { switch(opt) { case i: case l: case r: printf(option: %c\n, opt); break; case f: printf(filename: %s\n, optarg); break; case :: printf(option needs a value\n); break; case ?: printf(unknown option: %c\n, optopt); break; } } for(; optind < argc; optind++) printf(argument: %s\n, argv*optind+);

$ ./argopt -i -lr hi there -f fred.c -q option: i option: l option: r filename: fred.c unknown option: q argument: hi there

getopt_long
#include <stdlib.h> #define _GNU_SOURCE #include <getopt.h> int main(int argc, char *argv[]) { int opt; struct option longopts[] = { ,initialize, 0, NULL, i-, ,file, 1, NULL, f-, ,list, 0, NULL, l-, ,restart, 0, NULL, r-, }; while((opt = getopt_long(argc, argv, :if:lr, longopts, NULL)) != -1) { switch(opt) { case i: case l: case r: printf(option: %c\n, opt); break; case f: printf(filename: %s\n, optarg); break; case :: printf(option needs a value\n); break; case ?: printf(unknown option: %c\n, optopt); break; } } for(; optind < argc; optind++) printf(argument: %s\n, argv*optind+); exit(0);

struct option { const char *name; int has_arg; int *flag; int val; };

$ ./longopt --initialize --list hi there --file fred.c -q option: i option: l filename: fred.c ./longopt: invalid option -- q unknown option: q argument: hi there

Environmental variable
getenv putenv Form: name=value getenv(name) - > returns value of name E.g getenv(HOME) -> returns /home/user returns null if requested variable does not exist If the variable exists but has no value, getenv succeeds and returns an empty string

getenv
#include<stdio.h> #include<stdlib.h> int main(int argc, char *argv[]) { char *value; value = getenv(argv[1]); printf(value of %s is %s, argv*1+, value); } ./env HOME Value of HOME is home/user

#include<stdio.h> #include<stdlib.h> int main(int argc, char *argv[]) { char *value; int i; for( i=1; i<argc; i++) { value = getenv(argv[i]); printf(value of %s is %s, argv[i], value); } } ./env HOME FRED Value of HOME is home/user Value of FRED is (null)

putenv
#include<stdio.h> #include<stdlib.h> int main(int argc, char *argv[]) { char *value; int i; value = getenv(argv[1]); printf(value of %s is %s\n, argv*1+, value); value=malloc(strlen(argc[1]) + strlen(argc[2]) + 2); strcpy(value, argv[1]); strcat(value, =); strcat(value, argc[2]); printf(Calling putenv:%s\n, value); putenv(value); //assigns new value to arg[1] value=getenv(argv[1]); printf(new value of %s is %s\n, argv*1+, value); } ./env HOME hello Value of HOME is /home/user Calling putenv:HOME=hello New value of HOME is hello

The environ variable


#include <stdlib.h> #include <stdio.h> extern char **environ; int main() { while(*environ) { printf(%s\n,*environ); environ++; } } $ ./showenv HOSTNAME=tilde.provider.com LOGNAME=neil MAIL=/var/spool/mail/neil TERM=xterm HOSTTYPE=i386 PATH=/usr/local/bin:/bin:/usr/bin: HOME=/usr/neil

Time and date


UNIX systems all use the same starting point for times and dates: midnight GMT on January 1, 1970. This is the start of the UNIX epoch and Linux is no exception. All times in a Linux system are measured as seconds since then. Times are handled using a defined type, a time_t.

#include <time.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { time_t the_time; time(&the_time); printf(The time is %ld\n, the_time); } ./time The time is 131561907

gmtime
The structure tm is defined to contain at least the following members

#include <time.h> #include <stdio.h> #include <stdlib.h> int main() { struct tm *tm_ptr; time_t the_time; time(&the_time); tm_ptr = gmtime(&the_time); printf(Raw time is %ld\n, the_time); printf(gmtime gives:\n); printf(date: %d/%d/%d\n, tm_ptr->tm_year, tm_ptr->tm_mon+1, tm_ptr->tm_mday); printf(time: %d:%d:%d\n, tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec); exit(0); }

./gm Raw time is 131565907 Gmtime gives Date: 111/9/10 Time : 12:51:11

ctime
#include <time.h> #include <stdio.h> #include <stdlib.h> int main() { time_t timeval; time(&timeval); char *r; r=ctime(&timeval); printf(The date is: %s, r); } $ ./ctime The date is: Sat Jun 9 08:02:08 2007

User Information
#include <sys/types.h>
int main() { uid_t uid; gid_t gid; uid= getuid(); gid=getgid(); printf(User is %s\n, getlogin()); printf(User IDs: uid=%d, gid=%d\n, uid, gid);

struct passwd *getpwuid(uid_t uid);

int main() { uid_t uid; gid_t gid; uid= getuid(); gid=getgid(); printf(User is %s\n, getlogin()); printf(User IDs: uid=%d, gid=%d\n, uid, gid); pw = getpwuid(uid); printf(UID name=%s,pw->pw_name); }

#include <stdio.h> #include <stdlib.h> char *menu[] = { a - add new record, d - delete record, q - quit, NULL, }; int getchoice(char *greet, char *choices[]); int main() { int choice = 0; do { choice = getchoice(Please select an action, menu); printf(You have chosen: %c\n, choice); - while(choice != q); exit(0); }

int getchoice(char *greet, char *choices[]) { int chosen = 0; int selected; char **option; do { printf(Choice: %s\n,greet); option = choices; while(*option) { printf(%s\n,*option); option++; } selected = getchar(); option = choices; while(*option) { if(selected == *option[0]) { chosen = 1; break; } option++; } if(!chosen) { printf(Incorrect choice, select again\n); } } while(!chosen); return selected; }

Você também pode gostar