shell syntax

1.Variables

xxx@xxx-pc ~ $ salutation=hello
xxx@xxx-pc ~ $ echo $salutation 
hello
xxx@xxx-pc ~ $ read salutation
what?   //user in
xxx@xxx-pc ~ $ echo $salutation 
what?

Try It Out:

#!/bin/sh

myvar="Hi there"

echo $myvar
echo "$myvar"
echo '$myvar'
echo \$myvar

echo Enter some text
read myvar

echo '$myvar' now equals $myvar
exit 0

-----------------------
//output:
Hi there
Hi there
$myvar
$myvar
Enter some text
Hello World     //user-in
$myvar now equals Hello World

Environment Variables

$HOME  //the home directory of the current user
$PATH  //a colon-separated list of directories to search for commands
$PS1	//a cmd prompt, frequently $.    [\u@\h \w] $ 
$PS2   //a secondary prompt, used when prompting for additional input; usually >.
$IFS   //an input field separator.separate word ,usually space
$0     //shell script
$#     //the number of parameters passed to script
$$		//process ID of shell script, use for example /tmp/tmpfile_$$

man env

Parameter Variables

$1,$2...   //parameters
$* //a list of parameters.
$@
--ex.
--------
xx@xxx-pc ~ $ IFS=''  /* '\0' */
xxx@xxx-pc ~ $ echo "$@"
foo bar bam
xxx@xxx-pc ~ $ echo "$*"
foobarbam
xxx@xxx-pc ~ $ unset IFS
xxx@xxx-pc ~ $ echo "$*"
foo bar bam

Try It Out

#!/bin/sh

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 user's home directory is $HOME"
echo "Please enter a new greeting"
read salutation
echo $salutation
echo "The script is now complete"
exit 0

------
------------------------
xxx@xxx-pc ~ $ sh 1.sh foo bar baz
Hello
The program 1.sh is now running
The second parameter was bar
The first parameter was foo
The parameter list was foo bar baz
The user's home directory is /home/xxx
Please enter a new greeting
sire    //user-in
sire
The script is now complete

Conditions

The test or [ Command

xxx@xxx-pc ~ $ which test
/usr/bin/test

check a file exists.

xxx@xxx-pc ~ $ if test -f 1.sh
> then echo test
> fi
test
/* or */
xxx@xxx-pc ~ $ if [ -f 1.sh ]; then echo test; fi
test

The condition types that you can use with the test command fall into three types: string comparison,arithmetic comparison, and file conditionals. The following table describes these condition types:

/* String Comparison  &  Result */
string1 = string2   //True if the strings are equal
string1 != string2  //True if the strings are not equal
-n string   //True if the string is not null
-z string   //True if the string is null (an empty string)

/* Arithmetic Comparison  &  Result */
expression1 -eq expression2   //True if the expressions are equal
expression1 -ne expression2   // not equal
expression1 -gt expression2   // greater than 
expression1 -ge expression2   // greater than or equal 
expression1 -lt expression2   // less than 
expression1 -le expression2   // less than or equal 
! expression    //True if the expression is false, and vice versa

/* File Conditional  &  Result */
-d file   //True if the file is a directory
-e file   /*True if the file exists. Note that historically the 
          -e option has not been portable, so -f is usually used.*/
-f file   //True if the file is a regular(普通) file
-g file   //True if set-group-id is set on file
-r file   //True if the file is readable
-s file   //True if the file has nonzero size
-u file   //True if set-user-id is set on file
-w file   //True if the file is writable
-x file   //True if the file is executable
#!/bin/sh

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
----
---------------
xxx@xxx-pc ~ $ sh 1.sh 
file /bin/bash exists
/bin/bash is NOT a directory

Control Structures

if

#!/bin/sh

echo "It is morning? Please answer yes or no"
read timeofday

if [ $timeofday = "yes" ]; then
  echo "Good morning"
else
  echo "Good afternoon"
fi

exit 0

-----
-----------------
xxx@xxx-pc ~ $ sh 1.sh 
It is morning? Please answer yes or no
yes     //user-in
Good morning

elif

Try It Out :

#!/bin/sh

echo "It is morning? Please answer yes or no"
read timeofday

if [ $timeofday = "yes" ]; then
  echo "Good morning"
elif [ $tmeofday = "no" ]; then
  echo "Good afternoon"
else
  echo "Sorry, $timeofday not recognized. Enter yes or no"
  exit 1
fi

exit 0
------
--------------------
xxx@xxx-pc ~ $ sh 1.sh 
It is morning? Please answer yes or no
                    //push Enter, is null
1.sh: 6: [: =: unexpected operator
1.sh: 8: [: =: unexpected operator
Sorry,  not recognized. Enter yes or no

/* so we should alter like:
if [ "$timeofday" = "yes" ]; then
*/

bash allows echo -n to suppress(去除) the new line.

for

#!/bin/sh

for foo in bar fud 43
do 
  echo $foo
done
exit 0
-------
------------------
xxx@xxx-pc ~ $ sh 1.sh 
bar
fud
43
/* find f*.sh */
#!/bin/sh

for file in $(ls f*.sh); do
  echo $file
done
exit 0

while

a rather poor password-checking program:

#!/bin/sh

echo "Enter password"
read trythis

while [ "$trythis" != "secret" ]; do
  echo "Sorry, try again"
  read trythis
done
exit 0

---------
------------------
Enter password
sss     //user-in
Sorry, try again
secret  //user-in

until

until condition
do
  statements
done

an until loop, you can set up an alarm that is initiated when another user, whose login name you pass on the command line**, logs on**

#!/bin/sh

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 ****"

exit 0

------
-------------------
xxx@xxx-pc ~ $ sh f1.sh xxx
-e 
**** xxx has just logged in ****

case

case variable in
  pattern [ | pattern] ...) statements;;
  pattern [ | pattern] ...) statements;;
  ...
esac
  1. User Input
#!/bin/sh

echo "Is it morning? Please answer yes or no"
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

exit 0

2 . Putting Patterns Together

#!/bin/sh

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

exit 0

3.Executing Multiple Statements

#!/bin/sh

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"
    exit 1
    ;;
esac 

exit 0
/* more powerful : [yY] | [Yy][Ee][Ss] ) */

Lists

The AND List
#!/bin/sh

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

exit 0
-----------
------------------------
hello
in else
The OR List

execute a series of commands until one succeeds, and then not execute any more.

#!/bin/sh

rm -f file_one

if [ -f file_one ] || echo "hello" || echo " there"
then
  echo "in if"
else
  echo "in else"
fi

exit 0

----
--------------------
hello
in if
[ -f file_one ] && command for true || command for false

Statement Blocks

{} to make a statement block.

get_confirm && {
    grep -v "$cdcatnum" $tracks_file > $temp_file
    cat $temp_file > $tracks_file
    echo 
    add_record_tracks
}

Functions

function_name () {
  statements
}
#!/bin/sh

foo() {
    echo "Function foo is executing"
}

echo "script starting"
foo
echo "script ended"

exit 0

----
----------------
script starting
Function foo is executing
script ended
#!/bin/sh

sample_text="global variable"
foo() {
    local sample_text="local_variable"
    echo "Function foo is executing"
    echo $sample_text
}

echo "script starting"
echo $sample_text
foo
echo "script ended"
echo $sample_text

exit 0
---------
-----------------
script starting
global variable
Function foo is executing
local_variable
script ended
global variable

Try It Out

#!/bin/sh

yes_or_no() {
    echo "Is your name $* ?"
    while true
    do
    echo -n "Enter yes or no: "
    read x
    case "$x" in
      y | yes) return 0;;
      n | no)  return 1;;
      *)       echo "Answer yes or no"
    esac
    done
}

echo "Original parameters are $*"

if yes_or_no "$1"
then 
  echo "Hi $1, nice name"
else
  echo "Never mind"
fi
exit 0

------
---------------
Original parameters are xxx
Is your name xxx ?
Enter yes or no: y
Hi xxx, nice name

Commands

break

#!/bin/sh

rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo > fred4

for file in fred*
do
    if [ -d "$file" ]; then
    break;
    fi
done

echo first directory starting fred was $file

rm -rf fred*
exit 0
----
--------------
first directory starting fred was fred3

The : Command

The colon command is a null command.

#!/bin/sh

rm -f fred
if [ -f fred ]; then
    :
else
    echo file fred did not exist
fi

exit 0

continue

#!/bin/sh

rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo > fred4

for file in fred*
do
    if [ -d "$file" ]; then
    echo "skipping directory $file"
    continue;
    fi
    echo file is $file
done

rm -rf fred*
exit 0

######
####
file is fred1
file is fred2
skipping directory fred3
file is fred4

continue can take the enclosing loop number at which to resume as an optional parameter so that you can partially jump out of nested loops. This parameter is rarely used, as it often makes scripts much harder to understand. For example

#!/bin/sh

for x in 1 2 3
do
    echo before $x
    continue 1
    echo after $x
done
exit 0
####
before 1
before 2
before 3

The . Command

usually create a subshell for a script.
The dot ( . ) command executes the command in the current shell:

. ./shell_script

set the environment

#!/bin/sh

version=classic
PATH=/usr/local/old_bin:/usr/bin:/bin:.
PS1="classic> "

-------------
#!/bin/sh

version=latest
PATH=/usr/local/new_bin:/usr/bin:/bin:.
PS1="latest version>"

#############
####
$ . ./classic_set
classic> echo $version
classic
classic> . ./latest_set
latest version> echo $version
latest
latest version>

The scripts are executed using the dot command, so each script is executed in the current shell. This enables the script to change environment settings in the current shell, which remains changed even when the script finishes executing.

echo

suppressing a newline

echo -nstring to output”  // linux
echo -estring to output\c”// \c for suppressing a newline

eval

The eval command enables you to evaluate arguments. It’s built into the shell and doesn’t normally exist as a separate command.

xxx@xxx-pc ~ $ foo=10
xxx@xxx-pc ~ $ x=foo
xxx@xxx-pc ~ $ y='$'$x
xxx@xxx-pc ~ $ echo $y
$foo
xxx@xxx-pc ~ $ foo=10
xxx@xxx-pc ~ $ x=foo
xxx@xxx-pc ~ $ eval y='$'$x
xxx@xxx-pc ~ $ echo $y
10

printf

printf “format string“ parameter1 parameter2 ...
$ printf%s\n” hello
hello
$ printf%s %d\t%s” “Hi There” 15 people
Hi There 15    people

return

return takes a single numeric parameter that is available to the script calling the function. If no parameter is specified, then return defaults to the exit code of the last command.

set

The set command sets the parameter variables for the shell.

#!/bin/sh
echo the date is $(date)
set $(date)
echo The month is $2
exit 0
#########
####
the date is Sat Sep 5 14:33:06 CST 2015
The month is Sep

This program sets the parameter list to the date command’s output and then uses the positional parameter $2 to get at the month.
set -xwhich makes a script display a trace of its currently executing command.

shift

The shift command moves all the parameter variables down by one.

you can scan through all the positional parameters like this:

#!/bin/sh
while [ "$1" != "" ]; do
    echo "$1"
    shift
done
exit 0

trap

The trap command is used to specify the actions to take on receipt(接收) of signals.
trap -l . detail : man 7 signal

trap command signal

To reset a trap condition to the default, simply specify the command as - .To ignore a signal, set the command to the empty string “” . A trap command with no parameters prints out the current list of traps and actions.

Signal   &  Description
HUP(1)  Hang up(挂起); usually sent when a terminal goes offline, or a user logs out
INT(2)  Interrupt(中断); usually sent by pressing Ctrl+C
QUIT(3)  Quit; usually sent by pressing Ctrl+\
ABRT(6)  Abort(中止); usually sent on some serious execution error
ALRM(14)  Alarm; usually used for handling timeouts
TERM(15)  Terminate(终止); usually sent by the system when it’s shutting down
#!/bin/sh

trap 'rm -f /tmp/my_tmp_file_$$' INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$

echo "press interrupt (CTRL_C) to interrupt ...."
while [ -f /tmp/my_tmp_file_$$ ]; do
    echo File exists
    sleep 1
done
echo The file no longer exists

trap INT      // null to do 
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$

echo "press interrupt (control-c) to interrupt ...."
while [ -f /tmp/my_tmp_file_$$ ]; do
    echo File exists
    sleep 1
done

echo we never get here
exit 0
##########
######

creating file /tmp/my_tmp_file_628
press interrupt (CTRL_C) to interrupt ....
File exists
File exists
File exists
^CThe file no longer exists
creating file /tmp/my_tmp_file_628
press interrupt (control-c) to interrupt ....
File exists
File exists
File exists
File exists
File exists
^C

unset

The unset command removes variables or functions from the environment. It can’t do this to read-only variables defined by the shell itself, such as IFS. It’s not often used.

#!/bin/sh

foo="Hello World"
echo $foo

unset foo
echo $foo
########
####
Hello World

Two More Useful Commands and Regular Expressions

The find Command
find / -name test -print
find / -mount -name test -print /* find quickly, don't search other filesystem directories*/
The full syntax for the find command is as follows:
find [path] [options] [tests] [actions]

There are several options; the main ones are shown in the following table:

Option   &  Meaning
-depth   Search the contents of a directory before looking at the directory itself.
-follow   Follow symbolic links.
-maxdepths N   Search at most N levels of the directory when searching.
-mount (or -xdev )   Don’t search directories on other file systems.

Now for the tests. A large number of tests can be given to find , and each test returns either true or false .

Test Meaning
-atime N   The file was last accessed N days ago.
-mtime N   The file was last modified N days ago.
-name pattern   The name of the file
-newer otherfile   The file is newer than otherfile .
-type C    type C, the most common are “d” for a directory and “f” for a regular file.
-user username   The file is owned by the user with the given name.

You can also combine tests using operators. Most have two forms: a short form and a longer form, as shown in the following table:

Operator,   Short Form Operator,   Long Form Meaning
!   -not   Invert the test.
-a   -and    Both tests must be true.
-o    -or    Either test must be true.

write the test “newer than file X or called a name that starts with an underscore,” you could write the following test:

\( -newer X -o -name "_*" \)

example:

$ find . -newer while2 -print
.
./elif3
./words.txt
./words2.txt
./_trap
###################
$ find . -newer while2 -type f -print
./elif3
./words.txt
./words2.txt
./_trap
find . \( -newer f1.sh -o -name "_*" \) -type f -print

//你必须转义圆括号保证不会被shell处理, 把*号用引号括起保证直接传递给find.

this is just a list of the most common actions:

Action   &  Meaning
-exec command   Execute a command. This action must be terminated with a \; character pair.
-ok command   Like -exec, prompts before executing. terminated with a \; character pair.
-print   Print out the name of the file.
-ls   Use the command ls -dils on the current file.

//-exec 和 -ok之后直到\; 都是其参数; 它们是嵌入式命令, 以\;结束.

The magic string “{}” is a special type of parameter to an -exec or -ok command and is replaced with the full path to the current file.

xxx@xxx-pc ~ $ find . -newer f1.sh -type f -exec ls -l {} \;
The grep Command

general regular expression parser.(通用正则表达式解析器) You use find to search your system for files, but you use grep to search files for strings. Indeed, it’s quite common to have grep as a command passed after -exec when using find .

grep [options] PATTERN [FILES]

If no filenames are given, it searches standard input.

Option   &  Meaning
-c    print a count of the number of lines that match.
-E    Turn on extended expressions.
-h    Suppress the normal prefixing of each output line with the name of the file it was found in.
-i    Ignore case.
-l    List the names of the files with matching lines; don’t output the actual matched line.
-v    Invert the matching pattern to select nonmatching lines, rather than matching lines.
$ grep in words.txt   //search "in"
When shall we three meet again. In thunder, lightning, or in rain?
I come, Graymalkin!
$ grep -c in words.txt words2.txt   
words.txt:2
words2.txt:14
$ grep -c -v in words.txt words2.txt
words.txt:9
words2.txt:16
Regular Expressions

certain characters are processed in a special way.

Character   &  Meaning
^    Anchor(指向) to the beginning of a line
$    Anchor to the end of a line
.    Any single character
[ ]    The square braces contain a range of characters, any one of which may be matched, such as a range of characters like a–e or an inverted range by preceding the range with a ^ symbol.
Match Pattern   &  Meaning
[:alnum:] Alphanumeric(字母和数字) characters
[:alpha:] Letters
[:ascii:] ASCII characters
[:blank:] Space or tab
[:cntrl:] ASCII control characters
[:digit:] Digits
[:graph:] Noncontrol, nonspace characters
[:lower:] Lowercase letters
[:print:] Printable characters
[:punct:] Punctuation(标点符号) characters
[:space:] Whitespace characters, including vertical tab
[:upper:] Uppercase letters
[:xdigit:] Hexadecimal(十六进制) digits

if the -E for extended matching is also specified, other characters that control the completion of matching may follow the regular expression . With grep it is also necessary to precede these characters with a \ .

Option   &  Meaning
?   Match is optional but may be matched at most once
*   Must be matched zero or more times
+   Must be matched one or more times
{n}   Must be matched n times
{n,}   Must be matched n or more times
{n,m}   Must be matched between n or m times, inclusive
xxx@xxx-pc ~ $ grep h$ *.sh    //line end in h
f1.sh:#!/bin/sh
f2.sh:#!/bin/sh
xxx@xxx-pc ~ $ grep h[[:blank:]] *.sh    //word end in h
f2.sh:echo The month is $2
xxx@xxx-pc ~ $ grep Th.[[:space:]] *.sh    //three-letter start with Th
f2.sh:echo The month is $2
xxx@xxx-pc ~ $ grep -E [a-z]\{5\} *.sh    //five-letter word
f1.sh:unset foo
f2.sh:echo The month is $2

Command Execution

#!/bin/sh
echo The current directory is $PWD
echo The current users are $(who)
exit 0
############
####
The current directory is /home/xxx
The current users are xxx tty8 2015-09-05 09:35 (:0) xxx pts/2 2015-09-05 13:47 (:0)

Since the current directory is a shell environment variable, the first line doesn’t need to use this command execution construct.

xxx@xxx-pc ~ $ whoisthere=$(who)
xxx@xxx-pc ~ $ echo $whoisthere
xxx tty8 2015-09-05 09:35 (:0) xxx pts/2 2015-09-05 13:47 (:0)

If you ever find yourself trying to convert a set of parameters that are the output of a command on standard output and capture(捕获) them as arguments for a program, you may well find the command xargs can do it for you.

Arithmetic Expansion

#!/bin/sh

x=0
while [ "$x" -ne 10 ]; do
    echo $x
    x=$(($x+1))
done

exit 0

Parameter Expansion

Parameter Expansion   &  Description
${param:-default}   If param is null, then set it to the value of default .
${#param}   Gives the length of param
${param%word}   From the end, removes the smallest part of param that matches word and returns the rest
${param%%word}   From the end, removes the longest part of param that matches word and returns the rest
${param#word}   From the beginning, removes the smallest part of param that matches word and returns the rest
${param##word}   From the beginning, removes the longest part of param that matches word and returns the rest
#!/bin/sh

unset foo
echo ${foo:-bar}

foo=fud
echo ${foo:-bar}

foo=/usr/bin/X11/startx
echo ${foo#*/}
echo ${foo##*/}

bar=/usr/local/etc/local/networks
echo ${bar%local*}
echo ${bar%%local*}

exit 0
##########
####
bar
fud
usr/bin/X11/startx
startx
/usr/local/etc/
/usr/

convert a GIF file into a JPEG file using the cjpeg program:

$ cjpeg image.gif > image.jpg
#!/bin/sh

for image in *.gif
do
    cjpeg $image > ${image%%gif}jpg
done

exit 0

Here Documents

One special way of passing input to a command from a shell script is to use a here document.

#!/bin/sh

cat <<!FUNKY!
hello
this is a here
document
!FUNKY
###########
####
hello
this is a here
document
#!/bin/sh

ed a_text_file <<!FunkyStuff!    // ed editor
3                 //move to 3rd line
d                 //delete
.,\$s/is/was/     //current line, replace
w               //write
q               //quit
!FunkyStuff!

exit 0
##########
####
xxx@xxx-pc ~ $ cat a_text_file
That is line 1
That is line 2
That was line 4

Debugging Scripts

Command Line | Option set Option | Description
sh -n <script> | set -o noexec   | Checks for syntax errors only;
               | set -n          | doesn’t execute commands
sh -v <script> | set -o verbose  | Echoes(回显) commands before
               | set -v          | running them
sh -x <script> | set -o xtrace   | Echoes commands after pro-
               | set -x          | cessing on the command line
sh -u <script> | set -o nounset  | Gives an error message when
               | set -u          | an undefined variable is used

For an initial check, you can use the command-line option, but for finer debugging, you can put the xtrace flags (setting an execu-
tion trace on and off) inside the script around the problem code. The execution trace causes the shell to print each line in the script, with variables expanded, before executing the line.

Use the following command to turn xtrace on:

set -o xtrace

Use this command to turn xtrace off again:

set +o xtrace

In the shell, you can also find out the program state wherever it exits by trapping the EXIT signal with a line something like the following placed at the start of the script:

trap ‘echo Exiting: critical variable = $critical_variableEXIT
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值