1. 程式人生 > 實用技巧 >7.shell指令碼程式設計

7.shell指令碼程式設計

1.shell 指令碼語言的基本用法

1.1shell 指令碼建立

1.格式要求:首行shebang機制

#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl 

2.新增執行許可權,在命令列上指定指令碼的絕對或者相對路徑,也可以執行指令碼直譯器直接執行指令碼

1.2指令碼的註釋規範

1、第一行一般為呼叫使用的語言

2、程式名,避免更改檔名為無法找到正確的檔案

3、版本號

4、更改後的時間

5、作者相關資訊

6、該程式的作用,及注意事項

7、最後是各版本的更新簡要說明

1.3指令碼的執行方式

[root@centos8 data]# cat shell.sh 
#!/bin/bash
ls
[root@centos8 data]# chmod +x shell.sh 
#相對路徑執行
[root@centos8 data]# ./shell.sh 
a.txt  b.txt  linxu.txt  message  passwd  shell.sh  systeminfo.sh  test  vimrc
#bash執行
[root@centos8 data]# bash shell.sh 
a.txt  b.txt  linxu.txt  message  passwd  shell.sh  systeminfo.sh  test  vimrc
#執行遠端主機的shell指令碼
[root@centos8 data]# #curl -s http://10.0.0.8/hello.sh|bash
[root@centos8 ~]#wget -qO - http://www.wangxiaochun.com/testdir/hello.sh |bash

1.4shell指令碼除錯

指令碼常見的3種錯誤:

  • 語法錯誤,後續的命令不繼續執行
  • 命令錯誤,預設後續的命令還會繼續執行,用bash -n 無法檢查出來 ,可以使用 bash -x 進行觀察
  • 邏輯錯誤,只能使用 bash -x 進行觀察

bash命令

bash -n:只檢測指令碼中的語法錯誤,但無法檢查出命令錯誤,但不真正執行指令碼

bash -x:除錯並執行指令碼

1.5變數

1.5.1 shell變數型別

內建變數,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE

使用者自定義變數

1.5.2 變數的定義和引用
  • 普通變數:生效範圍為當前shell程序;對當前shell之外的其它shell程序,包括當前shell的子shell 程序均無效
  • 環境變數:生效範圍為當前shell程序及其子程序
  • 本地變數:生效範圍為當前shell程序中某程式碼片斷,通常指函式

變數賦值

#變數的賦值可以是以下多種形式
直接字串:name='root'
變數引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)

變數引用

$name
${name}

範例

[root@centos8 data]# name='xiaoming'
[root@centos8 data]# echo $name
xiaoming

[root@centos8 data]# user='yonghu'
[root@centos8 data]# name="$user"
[root@centos8 data]# echo $name
yonghu

[root@centos8 data]# name=`ls -l /data/`
[root@centos8 data]# echo $name
total 8 -rw-r--r-- 1 root root 403 Jan 2 17:39 systeminfo.sh -rw-r--r-- 1 root root 110 Jan 3 10:17 test
[root@centos8 data]# echo "$name"
total 8
-rw-r--r-- 1 root root 403 Jan  2 17:39 systeminfo.sh
-rw-r--r-- 1 root root 110 Jan  3 10:17 test

範例:變數追加值

[root@centos8 data]# echo $user
yonghu
[root@centos8 data]# user+=:xiaoming
[root@centos8 data]# echo $user
yonghu:xiaoming

顯示和刪除變數

#set檢視所有變數
#unset <name>刪除指定變數
#使用上述方式設定變數是臨時保存於記憶體當中,當退出終端就會銷燬
1.5.3 環境變數

說明

  • 子程序(包括孫子程序)可以繼承父程序的變數,但是無法讓父程序使用子程序的變數
  • 一旦子程序修改從父程序繼承的變數,將會新的值傳遞給孫子程序
  • 一般只在系統配置檔案中使用,在指令碼中較少使用

環境變數的宣告和賦值

#宣告並賦值
export name=VALUE
declare -x name=VALUE
#或者分兩步實現
name=VALUE
export name

變數引用:

$name
${name}

顯示所有環境變數:

env
printenv
export
declare -x	

刪除變數

unset				

bash的內建環境變數

PATH
SHELL
USER
UID
HOME
PWD
SHLVL #shell的巢狀層數,即深度
LANG
MAIL
HOSTNAME
HISTSIZE
_   #下劃線 表示前一命令的最後一個引數
1.5.4 只讀變數

只能宣告定義,但後續不能修改和刪除,即常量;退出當前終端可以銷燬宣告的只讀變數

宣告只讀變數:

readonly name
declare -r name

檢視只讀變數

readonly [-p]
declare -r
1.5.5 變數位置

在bash shell中內建的變數, 在指令碼程式碼中呼叫通過命令列傳遞給指令碼的引數

$1, $2, ... 對應第1個、第2個等引數,shift [n]換位置
$0 命令本身,包括路徑
$* 傳遞給指令碼的所有引數,全部引數合為一個字串
$@ 傳遞給指令碼的所有引數,每個引數為獨立字串
$# 傳遞給指令碼的引數的個數
#清空所有位置變數
set --

範例

[root@centos8 data]# cat arg.sh 
#!/bin/bash
echo "arg1 is $1"
echo "arg1 is $2"
echo "arg1 is $3"
echo "the number of arg is $#"
echo "all args is $*"
echo "all args is $@"
echo "the script name is `basename $0`"

[root@centos8 data]# bash arg.sh {1..5}
arg1 is 1
arg1 is 2
arg1 is 3
the number of arg is 5
all args is 1 2 3 4 5
all args is 1 2 3 4 5
the script name is arg.sh

rm命令修改

#使用者使用rm命令時不刪除檔案而是移動到/tmp資料夾
[root@centos8 data]# cat rm.sh 
COLOR="echo -e \E[1;31m"
END="\E[0m"
DIR=/tmp/`date +%F_%H-%M-%S`
mkdir $DIR
mv $* $DIR
$COLOR move $* to $DIR $END
1.5.6 退出狀態碼

$?

$?的值為0,代表成功

$?的值是1到255 #代表失敗

注意:

  • 如果未給指令碼指定退出狀態碼,整個指令碼的退出狀態碼取決於指令碼中執行的最後一條命令的狀態碼
1.5.7 指令碼安全和 set

$- 變數

[root@centos8 data]# echo $-
himBHs

h:hashall,開啟選項後,Shell 會將命令所在的路徑hash下來,避免每次都要查詢。通過set +h將h選 項關閉

i:interactive-comments,包含這個選項說明當前的 shell 是一個互動式的 shell。所謂的互動式shell, 在指令碼中,i選項是關閉的 m:monitor,開啟監控模式,就可以通過Job control來控制程序的停止、繼續,後臺或者前臺執行等

B:braceexpand,大括號擴充套件

H:history,H選項開啟,可以展開歷史列表中的命令,可以通過!感嘆號來完成,例如“!!”返回上最近的 一個歷史命令,“!n”返回第 n 個歷史命令

set 命令

-u 在擴充套件一個沒有設定的變數時,顯示錯誤資訊, 等同set -o nounset

-e 如果一個命令返回一個非0退出狀態值(失敗)就退出, 等同set -o errexit

-o option 顯示,開啟或者關閉選項

​ 顯示選項:set -o

​ 開啟選項:set -o 選項

​ 關閉選項:set +o 選項

1.6 printf

printf:格式化要輸出的資料

printf FORMAT [ARGUMENT]...

常用格式替換符

  • %s 字串

  • %f 浮點格式

  • %b 相對應的引數中包含轉義字元時,可以使用此替換符進行替換,對應的轉義字元會被轉 義

  • %c ASCII字元,即顯示對應引數的第一個字元

  • %d,%i 十進位制整數

  • %o 八進位制值

  • %u 不帶正負號的十進位制值

  • %x 十六進位制值(a-f)

  • %X 十六進位制值(A-F)

  • %% 表示%本身

  • %s 中的數字代表此替換符中的輸出字元寬度,不足補空格,預設是右對齊,%-10s表示10個字 符寬,- 表示左對齊

常用轉義字元

  • \a 警告字元,通常為ASCII的BEL字元
  • \n 換行
  • \r 回車
  • \t 水平製表符
  • \v 垂直製表符

範例

[root@centos8 data]# printf "%d\n" 123 321 123
123
321
123

[root@centos8 data]# printf "(%s) " 1 2 3
(1) (2) (3) [root@centos8 data]# 
[root@centos8 data]# printf "(%s) " 1 2 3;echo 
(1) (2) (3) 
[root@centos8 data]# printf "(%s) " 1 2 3;echo ""
(1) (2) (3) 


[root@centos8 data]# printf "%10s" name;echo
      name

1.7算術運算

shell 支援算術運算,但只支援整數,不支援小數

shell運算子

+
-
*
/
% 取模,即取餘數,示例:9%4=1,5%3=2
** 乘方

實現算數運算的方式

1.	let var=算數表示式
2.	((var=算數表示式))
3.	var=$[算數表示式]
4.	var=$((算數表示式))
5.	delare -i var = 數值
6. echo '算術表示式' | bc 
7.	var=$(expr arg1 arg2 arg3 ...)

範例

#生成 1 - 50 之間隨機數
[root@centos8 data]# echo $[RANDOM%50+1]
12

增強型賦值:

+= i+=10 相當於 i=i+10
-= i-=j   相當於 i=i-j
*=
/=
%=
++ i++,++i   相當於 i=i+1
-- i--,--i   相當於 i=i-1

範例

#i++和++i
[root@centos8 ~]#unset i j ; i=1; let j=i++; echo "i=$i,j=$j"
i=2,j=1
[root@centos8 ~]#unset i j ; i=1; let j=++i; echo "i=$i,j=$j"
i=2,j=2

#使用計算器實現浮點運算
[root@centos8 data]# echo "scale=3;20/3" | bc
6.666

1.8邏輯運算

與:&:和0相與,結果為0,和1相與,結果保留原值

1 與 1 = 1 
1 與 0 = 0 
0 與 1 = 0 
0 與 0 = 0

或:|:和1相或結果為1,和0相或,結果保留原值

 1 或 1 = 1
 1 或 0 = 1
 0 或 1 = 1
 0 或 0 = 0 

非:!

 ! 1 = 0 ! true
 ! 0 = 1 ! false

異或:^

相同為假,不同為真。

1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0 

範例

#注意區分邏輯運算的二進位制值與$?的返回值含義剛好相反
#利用異或可以實現兩個變數的數值交換
[root@centos8 data]# x=30;y=20;x=$[x^y];y=$[x^y];x=$[y^x];echo "x=$x y=$y"
x=20 y=30

短路運算

  • 短路與

    CMD1 短路與 CMD2

    第一個CMD1結果為假 (0),總的結果必定為0,因此不需要執行CMD2

  • 短路或

    CMD1 短路或 CMD2

    第一個CMD1結果為真 (1),總的結果必定為1,因此不需要執行CMD2

1.9條件測試命令

若真,則狀態碼變數 $? 返回0

若假,則狀態碼變數 $? 返回1

條件測試命令:

  • test EXPRESSION
  • [ EXPRESSION ] #和test 等價,建議使用 [ ]
  • [[ EXPRESSION ]]

檢視幫助

[root@centos8 data]# help [
[root@centos8 data]# help test
選項
		-a FILE        True if file exists.
      -b FILE        True if file is block special.
      -c FILE        True if file is character special.
      -d FILE        True if file is a directory.
      -e FILE        True if file exists.
      -f FILE        True if file exists and is a regular file.
      -g FILE        True if file is set-group-id.
      -h FILE        True if file is a symbolic link.
      -L FILE        True if file is a symbolic link.
      -k FILE        True if file has its `sticky' bit set.
      -p FILE        True if file is a named pipe.
      -r FILE        True if file is readable by you.
      -s FILE        True if file exists and is not empty.
      -S FILE        True if file is a socket.
      -t FD          True if FD is opened on a terminal.
      -u FILE        True if the file is set-user-id.
      -w FILE        True if the file is writable by you.
      -x FILE        True if the file is executable by you.
      -O FILE        True if the file is effectively owned by you.
      -G FILE        True if the file is effectively owned by your group.
      -N FILE        True if the file has been modified since it was last read.
    
    String operators:
    
      -z STRING      True if string is empty.
    
      -n STRING
         STRING      True if string is not empty.
    
      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.
   
    Other operators:
#變數測試    
      -o OPTION      True if the shell option OPTION is enabled.
      -v VAR         True if the shell variable VAR is set.
      -R VAR         True if the shell variable VAR is set and is a name
                     reference.
      ! EXPR         True if expr is false.
      EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
      EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.
#數值測試    
      arg1 OP arg2   Arithmetic tests.  OP is one of -eq, -ne,
                     -lt, -le, -gt, or -ge.
    
    Arithmetic binary operators return true if ARG1 is equal, not-equal,
    less-than, less-than-or-equal, greater-than, or greater-than-or-equal
    than ARG2.

1.9.1變數測試

範例

#判斷 NAME 變數是否定義
[ -v NAME ] 
#判斷 NAME 變數是否定義並且是否引用
[ -R NAME ]

[root@centos8 data]# echo $name

[root@centos8 data]# [ -v name ]
[root@centos8 data]# echo $?
1
[root@centos8 data]# name="xiaoming"
[root@centos8 data]# [ -v name ]
[root@centos8 data]# echo $?
0

[root@centos8 data]# [ -R name ]
[root@centos8 data]# echo $?
1
[root@centos8 data]# [ -v name ]
[root@centos8 data]# echo $?
0
1.9.1數值測試

範例

[root@centos8 data]# i=10;j=20;
[root@centos8 data]# [ i -eq j ]
-bash: [: i: integer expression expected
[root@centos8 data]# [ $i -eq $j ]
[root@centos8 data]# echo $?
1
1.9.2字串測試

範例

[root@centos8 data]# echo $name

[root@centos8 data]# [ -z $name ]
[root@centos8 data]# echo $?
0
[root@centos8 data]# unset name
[root@centos8 data]# [ -z $name ]
[root@centos8 data]# echo $?
0
[root@centos8 data]# name=xiaoming
[root@centos8 data]# [ -z "$name" ]
[root@centos8 data]# echo $?
1

[ ]用法

[[]] 用法,建議,當使用正則表示式或萬用字元使用,一般情況使用 [ ]

== 左側字串是否和右側的PATTERN相同
 注意:此表示式用於[[ ]]中,PATTERN為萬用字元

=~ 左側字串是否能夠被右側的正則表示式的PATTERN所匹配
 注意: 此表示式用於[[ ]]中;擴充套件的正則表示式

範例

[root@centos8 data]# NAME=linux
[root@centos8 data]# [[ "$NAME" == linu\* ]]
[root@centos8 data]# echo $?
1
[root@centos8 data]# [[ "$NAME" == linu* ]]
[root@centos8 data]# echo $?
0
#結論:[[ == ]] == 右側的 * 做為萬用字元,不要加“”,只想做為*, 需要加“” 或轉義
1.9.3 檔案測試

範例

[root@centos8 data]# [ -a /data/test ]
[root@centos8 data]# echo $?
0
[root@centos8 data]# ![ -a /data/test ]
[ -a /data/test ] -a /data/test ]
-bash: [: too many arguments
[root@centos8 data]# ! [ -a /data/test ]
[root@centos8 data]# echo $?
1
[root@centos8 data]# [ -w /etc/shadow ]
[root@centos8 data]# echo $?
0

1.10 () 和 {}

(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以將多個命令組合在一起,批量執行。使用man bash可以檢視幫助

區別

( list ) 會開啟子shell,並且list中變數賦值及內部命令執行後,將不再影響後續的環境

{ list; } 不會啟子shell, 在當前shell中執行,會影響當前shell環境

範例

[root@centos8 data]# echo $BASHPID
164220
[root@centos8 data]# ( echo $BASHPID;sleep 100)
164450
sshd(976)───sshd(164206)───sshd(164219)───bash(164220)─┬─bash(164449)───sleep(164450)
[root@centos8 data]# echo $BASHPID
164220
[root@centos8 data]# { echo $BASHPID;}
16422

1.11 組合測試條件

1.11.1 第一種方式

​ [ EXPRESSION1 -a EXPRESSION2 ] 並且,EXPRESSION1和EXPRESSION2都是真,結果才為真

​ [ EXPRESSION1 -o EXPRESSION2 ] 或者,EXPRESSION1和EXPRESSION2只要有一個真,結果就為 真

​ [ ! EXPRESSION ] 取反

範例

[root@centos8 data]# FILE=/data/test
[root@centos8 data]# [ -f $FILE -a -x $FILE ]
[root@centos8 data]# echo $?
1
[root@centos8 data]# chmod +x /data/test
[root@centos8 data]# ll
total 20
-rw-r--r-- 1 root root   0 Jan  9 22:28 a.log
-rw-r--r-- 1 root root 181 Jan  4 18:29 arg.sh
-rw-r--r-- 1 root root   1 Jan  6 19:17 lx.txt
-rw-r--r-- 1 root root 116 Jan  5 15:50 rm.sh
-rw-r--r-- 1 root root 403 Jan  2 17:39 systeminfo.sh
-rwxr-xr-x 1 root root 110 Jan  3 10:17 test
[root@centos8 data]# [ -f $FILE -a -x $FILE ]
[root@centos8 data]# echo $?
0
1.11.2 第二種方式

COMMAND1 && COMMAND2 並且,短路與,代表條件性的AND THEN 如果COMMAND1 成功,將執行COMMAND2,否則,將不執行COMMAND2

COMMAND1 || COMMAND2 或者,短路或,代表條件性的OR ELSE 如果COMMAND1 成功,將不執行COMMAND2,否則,將執行COMMAND2

! COMMAND #非,取反

範例

[root@centos8 data]# test "A" = "B" && echo "string are equal"
[root@centos8 data]# test "A" = "A" && echo "string are equal"
string are equal

[root@centos8 data]# ll
-rw-r--r-- 1 root root 110 Jan  3 10:17 test.sh
[root@centos8 data]# [ -f $FILE ] && [[ $FILE =~ \.sh$ ]] && chmod +x $FILE

[root@centos8 data]# ll
-rwxr-xr-x 1 root root 110 Jan  3 10:17 test.sh

&&與||組合使用

[root@centos8 data]# NAME=user;id $NAME && echo "$NAME is exist" || echo "$NAME is not exist"
uid=1001(user) gid=1001(user) groups=1001(user)
user is exist
#注意:如果&& 和 || 混合使用,&& 要在前,|| 放在後。否則會出現邏輯錯誤

1.12 read命令

read:使用read來把輸入值分配給一個或多個shell變數,read從標準輸入中讀取值,給每個單詞分配一個變 量,所有剩餘單詞都被分配給最後一個變數,如果變數名沒有指定,預設標準輸入的值賦值給系統內建 變數REPLY

read [options] [name ...]

常用選項

  • -p 指定要顯示的提示
  • -s 靜默輸入,一般用於密碼
  • -n N 指定輸入的字元長度N
  • -d '字元' 輸入結束符
  • -t N TIMEOUT為N秒

範例

[root@centos8 data]# read
username
[root@centos8 data]# echo $REPLY
username
[root@centos8 data]# read NAME SEX
xiaoming boy
[root@centos8 data]# echo $NAME $SEX
xiaoming boy
[root@centos8 data]# read -p "please input your name:" NAME
please input your name:daxiong 
[root@centos8 data]# echo $NAME
daxiong

面試題 read和輸入重定向
[root@centos8 data]# echo 1 2 | read x y;echo $x $y

[root@centos8 data]# echo 1 2 | (read x y;echo $x $y)
1 2
#Each command in a pipeline is executed as a separate process (i.e., in  a subshell)
#管道符把每個命令執行都在獨立的子程序中,所以第一種情況父程序無法讀取子程序的變數

2 bash的配置檔案

2.1 配置檔案分類

全域性生效配置檔案

/etc/profile
/etc/profile.d/*.sh
/etc/bashrc

個人使用者生效配置檔案

~/.bash_profile
~/.bashrc

2.2 配置檔案載入順序

2.2.1 互動式登入順序
  • 直接通過終端輸入賬號密碼登入
  • 使用 su - UserName 切換的使用者

配置檔案載入順序

/etc/profile.d/*.sh
/etc/bashrc
/etc/profile
/etc/bashrc    #此檔案執行兩次
.bashrc
.bash_profile
2.2.2 非互動式順序
  • su UserName
  • 圖形介面下開啟的終端
  • 執行指令碼
  • 任何其他的bash例項

配置檔案載入順序

/etc/profile.d/*.sh
/etc/bashrc
.bashrc

2.3 配置檔案分類

2.3.1 Profile類

為互動式登入的shell提供配置

全域性:/etc/profile, /etc/profile.d/*.sh
個人:~/.bash_profile

用途:

1)用於定義環境變數

2)執行指令碼或命令

2.3.2 Bashrc類

為非互動式和互動式登入的shell提供配置

全域性:/etc/bashrc
個人:~/.bashrc

用途:

1)定義命令別名和函式

2)定義本地變數

2.3.3 配置檔案生效方式
  1. 重新啟動shell程序
  2. source|. 配置檔案

3.流程控制

3.1 條件判斷if

格式

if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi

範例

#BMI指數
[root@centos8 script]# cat bmi.sh 
#!/bin/bash
#
#********************************************************************
#Author:		yuanyuan
#QQ: 			1136132605
#Date: 			2021-01-11
#FileName:		bmi.sh
#URL: 			http://www.bestvae.cn
#Description:		The test script
#Copyright (C): 	2021 All rights reserved
#********************************************************************
read -p "請輸入身高(單位m)" HIGH
if [[ ! "$HIGH" =~ ^[0-2]\.?[0-9]{,2}$ ]];then
        echo "輸入身高錯誤"
        exit 1
fi
read -p "請輸入體重(單位kg)" WEIGHT
if [[ ! "$WEIGHT" =~ ^[0-9]{1,3}$ ]];then
        echo "輸入體重錯誤"
        exit 1
fi
BMI=`echo $WEIGHT/$HIGH^2|bc`
if [ "$BMI" -le 18 ];then
        echo "你太瘦了多吃點"
elif [ "$BMI" -lt 24 ];then
        echo "你的身材很棒"
else
        echo "你太胖了,加強運動"
fi

3.2 條件判斷 case 語句

格式

case: case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
    Execute commands based on pattern matching.	
    
#case支援全域性萬用字元
*: 任意長度任意字元
?: 任意單個字元
[]:指定範圍內的任意單個字元
|:   或,如 a或b

範例

#運維表
#!/bin/bash
echo -en "\E[$[RANDOM%7+31];1m"
cat <<EOF
1)備份資料庫
2)清理日誌
3)軟體升級
4)軟體回退
5)刪庫跑路
EOF
echo -en '\E[0m'
read -p "請輸入上面的數字:" MENU
if [[ ! "$MENU" =~ ^[1-5]$ ]];then
        echo "你的輸入有誤"
        exit 1
fi
case $MENU in
1)
    echo "備份成功";;
2)
    echo "清理日誌";;                  
3)
    echo "清理日誌";;        
4)
    echo "清理日誌";;        
5)          
    echo "清理日誌";;                  
esac

練習

1、編寫指令碼 createuser.sh,實現如下功能:使用一個使用者名稱做為引數,如果指定引數的使用者存在,就 顯示其存在,否則新增之。並設定初始密碼為123456,顯示新增的使用者的id號等資訊,在此新使用者第一 次登入時,會提示使用者立即改密碼,如果沒有引數,就提示:請輸入使用者名稱

[root@centos8 script]# cat creatuser.sh 
#!/bin/bash

if [ -z "$1" ];then
    echo "請輸入使用者名稱字格式為$0 username"
    exit 1
else
    getent passwd $1 > /dev/null
    if [ "$?" -eq 0 ];then
        echo "$1 is exist" 
        echo `getent passwd $1`
        exit 1
    else
        useradd $1
        echo '123456' | passwd --stdin $1 > /dev/null
        passwd -e $1 > /dev/null
        echo -e "$1使用者建立成功初始密碼為123456\n`getent passwd $1`"                                                                           
   fi
fi

2、編寫生成指令碼基本格式的指令碼,包括作者,聯絡方式,版本,時間,描述等

[root@centos8 script]# cat /root/.vimrc 
set ts=4
set expandtab
set ignorecase
set cursorline
set autoindent
set showcmd
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
	if expand("%:e") == 'sh'
	call setline(1,"#!/bin/bash") 
	call setline(2,"#") 
	call setline(3,"#********************************************************************") 
	call setline(4,"#Author:	    yuanyuan") 
	call setline(5,"#QQ: 			1136132605") 
	call setline(6,"#Date: 			".strftime("%Y-%m-%d"))
	call setline(7,"#FileName:		".expand("%"))
	call setline(8,"#URL: 			http://www.bestvae.cn")
	call setline(9,"#Description:		The test script") 
	call setline(10,"#Copyright (C): 	".strftime("%Y")." All rights reserved")
	call setline(11,"#********************************************************************") 
	call setline(12,"") 
	endif
endfunc
autocmd BufNewFile * normal G