zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Shell Scripting part3

2023-09-14 09:13:32 时间

A function may return a value in one of four different ways:

  • Change the state of a variable or variables
  • Use the exit command to end the shell script
  • Use the return command to end the function, and return the supplied value to the calling section of the shell script
  • echo output to stdout, which will be caught by the caller just as c=`expr $a + $b` is caught
[maxwell@oracle-db-19c shell_20230320]$ cat function.sh 
#!/bin/sh
# A simple script with a function...

add_a_user()
{
  USER=$1
  PASSWORD=$2
  shift; shift;
  #Having shifted twice, the rest is now comments...
  COMMENTS=$@
  echo "Adding user $USER ..."
  echo useradd -c "$COMMENTS" $USER
  echo passwd $USER $PASSWORD
  echo "Added user $USER ($COMMENTS) with pass $PASSWORD"
}


###
# Main body of script starts here
###

echo "Start of script..."
add_a_user bob letmein Bob Holness the presenter
add_a_user fred badpassword Fred Durst the singer
add_a_user bilko worsepassword Sgt. Bilko the role model
echo "End of Script..."
[maxwell@oracle-db-19c shell_20230320]$ 

Scope of Variables

Programmers used to other languages may be surprised at the scope rules for shell functions. Basically, there is no scoping, other than the parameters ($1$2$@, etc).

The $@ parameters are changed within the function to reflect how the function was called. The variable x, however, is effectively a global variable - myfunc changed it, and that change is still effective when control returns to the main script.

$ ./scope.sh a b c
Script was called with a b c
x is 1
I was called as : 1 2 3
x is 2
$ 
$ cat scope.sh 
#!/bin/sh

myfunc()
{
  echo "I was called as : $@"
  x=2

}

### Main script starts here

echo "Script was called with $@"
x=1
echo "x is $x"
myfunc 1 2 3
echo "x is $x"
$ 

Recursion

Functions can be recursive - here's a simple example of a factorial function:

$ ./factorial.sh
Enter a number:
4
24
Enter a number:
2
2
Enter a number:
5
120
Enter a number:
6
720
Enter a number:
7
5040
Enter a number:
^C
$ cat factorial.sh 
#!/bin/sh

factorial()
{
  if [ "$1" -gt "1" ]; then
    i=`expr $1 - 1`
    j=`factorial $i`
    k=`expr $1 \* $j`
    echo $k
  else
    echo 1
  fi

}


while :
do
  echo "Enter a number:"
  read x
  factorial $x

done
$ 
$ 
$ cat common.lib 
# common.lib
# Note no #!/bin/sh as this should not spawn
# an extra shell. It's not the end of the world
# to have one, but clearer not to.
#
STD_MSG="About to rename some files..."

rename()
{
 

  # expects to be called as: rename .txt .bak 
  FROM=$1
  TO=$2

  for i in *$FROM
  do
    j=`basename $i $FROM`
    mv $i ${j}$TO
  done           
           
           
}
$ cat function2.sh 
#!/bin/sh
#function2.sh
. ./common.lib
echo $STD_MSG
rename .txt .bak
$ 
$ cat function3.sh 
#!/bin/sh
# function2.sh
. ./common.lib
echo $STD_MSG
rename .html .html-bak
$ 

Return Codes

#!/bin/sh

adduser()
{
  USER=$1
  PASSWORD=$2
  shift ; shift
  COMMENTS=$@
  useradd -c "${COMMENTS}" $USER
  if [ "$?" -ne "0" ]; then
    echo "Useradd failed"
    return 1
  fi
  passwd $USER $PASSWORD
  if [ "$?" -ne "0" ]; then
    echo "Setting password failed"
    return 2
  fi
  echo "Added user $USER ($COMMENTS) with pass $PASSWORD"
}

## Main script starts here

adduser bob letmein Bob Holness from Blockbusters
ADDUSER_RETURN_CODE=$?
if [ "$ADDUSER_RETURN_CODE" -eq "1" ]; then
  echo "Something went wrong with useradd"
elif [ "$ADDUSER_RETURN_CODE" -eq "2" ]; then 
   echo "Something went wrong with passwd"
else
  echo "Bob Holness added to the system."
fi

grep is an extremely useful utility for the shell script programmer.
An example of grep would be:

$ 
$ grep -i maxwell /etc/passwd
maxwell:x:1000:1000:maxwell:/home/maxwell:/bin/bash
$ grep -i maxwell /etc/passwd | cut -d: -f1
maxwell
$ vim grep_maxwell.sh
$ chmod 775 grep_maxwell.sh
$ 
$ ./grep_maxwell.sh
All users with the word "maxwell" in their passwd
Entries are: maxwell
$ 
$ grep -i maxwell /etc/passwd
maxwell:x:1000:1000:maxwell:/home/maxwell:/bin/bash
$ 
$ grep -i maxwell /etc/passwd |cut -d: -f1
maxwell
$ 
$ cat grep_maxwell.sh
#!/bin/sh
maxwell=`grep -i maxwell /etc/passwd | cut -d: -f1`
echo "All users with the word \"maxwell\" in their passwd"
echo "Entries are: $maxwell"
$ 
$ vim grep_maxwell_tr.sh     
$ chmod 775 grep_maxwell_tr.sh
$ 
$ ./grep_maxwell_tr.sh
All users with the word maxwell in their passwd
Entries are: 
MAXWELL
$ 
$ cat grep_maxwell_tr.sh 
maxwell=`grep -i maxwell /etc/passwd | cut -d: -f1`
echo "All users with the word "maxwell" in their passwd"
echo "Entries are: "
echo "$maxwell" | tr ' ' '\012' | tr '[a-z]' '[A-Z]'
$ 

Cheating

Cheating with awk

Consider wc, which counts the number of characters, lines, and words in a text file.

[maxwell@oracle-db-19c shell_20230320]$ PS1="$ " ; export PS1
$ 
$ wc grep_maxwell.sh
  4  23 150 grep_maxwell.sh
$ 

AWK是一种用于文本处理的编程语言和工具,可在shell中使用。AWK以行为单位对输入数据进行处理,并按照用户指定的规则进行分割、过滤和格式化输出。

AWK命令由三部分组成:模式(pattern)、动作(action)和输入文件(input file)。模式用来匹配输入数据中的某些内容,动作定义了当模式匹配到输入数据时要执行的操作,输入文件则指定要处理的数据源。

常见的AWK用途包括:

  1. 格式化文本数据输出
  2. 进行文本搜索和替换
  3. 统计和分析文本数据

 

If we want to get the number of lines into a variable, simply using:

$ NO_LINES=`wc -l grep_maxwell.sh | awk '{print $1}'`            
$ echo ${NO_LINES}
4
$ 

Cheating with sed

Another handy utility is sed - the stream editor. we can quickly use the s/from/to/g construct by invoking sed.

$ touch test.txt
$ vim test.txt
$ 
$ cat test.txt
This line is okay.
This line contains a bad word. Treat with care.
This line is fine, too.

There is nothing wrong with cheating! Some things the shell just isn't very good at. Two useful tools are sed and awk. Whilst these are two hugely powerful utilities, which can be used as mini- programming languages in their own right, they are often used in shell scripts for very simple, specific reasons.
$ 
$ sed s/line/lines/g test.txt > test_result.txt
$ cat test_result.txt
This lines is okay.
This lines contains a bad word. Treat with care.
This lines is fine, too.

There is nothing wrong with cheating! Some things the shell just isn't very good at. Two useful tools are sed and awk. Whilst these are two hugely powerful utilities, which can be used as mini- programming languages in their own right, they are often used in shell scripts for very simple, specific reasons.
$ 

sed是一种流编辑器,也是在shell中用于文本处理的工具。它可以按照指定的规则对输入数据进行编辑、替换、删除和添加等操作,并将结果输出到标准输出或者文件中。

sed命令由一个或多个编辑命令组成,每个命令都包含一个地址范围和一个操作。地址范围指定了进行操作的行或者行的范围,操作则定义了要执行的编辑动作。

常见的sed用途包括:

  1. 查找和替换文本
  2. 对文本进行格式化输出
  3. 选择性地显示或删除文本行

15. Quick Reference

CommandDescriptionExample
&Run the previous command in the backgroundls &
&&Logical ANDif [ "$foo" -ge "0" ] && [ "$foo" -le "9"]
||Logical ORif [ "$foo" -lt "0" ] || [ "$foo" -gt "9" ]
^Start of linegrep "^foo"
$End of linegrep "foo$"
=String equality (cf. -eq)if [ "$foo" = "bar" ]
!Logical NOTif [ "$foo" != "bar" ]
$$PID of current shellecho "my PID = $$"
$!PID of last background commandls & echo "PID of ls = $!"
$?exit status of last commandls ; echo "ls returned code $?"
$0Name of current command (as called)echo "I am $0"
$1Name of current command's first parameterecho "My first argument is $1"
$9Name of current command's ninth parameterecho "My ninth argument is $9"
$@All of current command's parameters (preserving whitespace and quoting)echo "My arguments are $@"
$*All of current command's parameters (not preserving whitespace and quoting)echo "My arguments are $*"
-eqNumeric Equalityif [ "$foo" -eq "9" ]
-neNumeric Inqualityif [ "$foo" -ne "9" ]
-ltLess Thanif [ "$foo" -lt "9" ]
-leLess Than or Equalif [ "$foo" -le "9" ]
-gtGreater Thanif [ "$foo" -gt "9" ]
-geGreater Than or Equalif [ "$foo" -ge "9" ]
-zString is zero lengthif [ -z "$foo" ]
-nString is not zero lengthif [ -n "$foo" ]
-ntNewer Thanif [ "$file1" -nt "$file2" ]
-dIs a Directoryif [ -d /bin ]
-fIs a Fileif [ -f /bin/ls ]
-rIs a readable fileif [ -r /bin/ls ]
-wIs a writable fileif [ -w /bin/ls ]
-xIs an executable fileif [ -x /bin/ls ]
( ... )Function definitionfunction myfunc() { echo hello }

IFS

在Shell中,IFS是"Internal Field Separator"的缩写。它是一个环境变量,用于指定用于分隔字段的字符或字符串。当解析命令时,Shell使用这个变量来确定如何拆分输入行的单词和空格。

默认情况下,IFS设置为包含空格、制表符和换行符的一组字符。这意味着Shell将使用这些字符来拆分命令行参数和标准输入数据流。

可以通过在脚本或命令中更改IFS值来自定义分隔符。例如,可以将IFS设置为逗号 "," 以使Shell使用逗号来拆分输入行。注意,在更改IFS之前,请保存原始值,并在完成后还原它,以避免对程序的其他部分造成影响。

IFS是一个环境变量,通常用于Shell脚本中,以指定分隔符来处理文本数据。以下是IFS的一些用法:

  1. 读取文件行并拆分字段:可以使用while循环读取文件的每一行,并在每次迭代时设置IFS为适当的分隔符(例如逗号或制表符),然后使用read命令将行拆分为字段。
#!/bin/bash
while IFS=',' read -r col1 col2 col3
do
    echo "Column 1: $col1"
    echo "Column 2: $col2"
    echo "Column 3: $col3"
done < data.csv

2.拆分字符串:可以使用IFS来拆分字符串为数组。例如,以下代码将使用空格作为分隔符拆分字符串为数组:

#!/bin/bash
string="Hello World"
IFS=' ' read -ra arr <<< "$string"

for i in "${arr[@]}"
do
   echo "$i"
done

3.实现命令替换:可以使用$(command)或反引号字符来执行命令,并使用IFS来拆分输出为数组。例如,以下代码使用IFS将df命令的输出拆分为一个数组:

#!/bin/bash
IFS=$'\n' df_output=($(df -h))

for line in "${df_output[@]}"
do
    echo "$line"
done

IFS是一个非常有用的变量,可用于处理文本数据和实现各种Shell编程任务。