[Linux command] Chapter 12: Learn shell script

Chapter 12 learning shell script Usually, she...
12.1 introduction to simple shell script
12.2 simple shell script exercise
12.3 make good use of judgment
12.4 condition judgment
12.5 loop
12.6 script tracking and debugging
Chapter 12 learning shell script

Usually, shell script is used to complete the detection of the server, which does not involve a lot of computation.

12.1 introduction to simple shell script

12.2 simple shell script exercise

12.2.1 simple example

Example 1: the beginning forever Helloworld
cat hello.sh //Output: #!/bin/bash #Program: # This program shows "hello world!" in your screen. #History: #2020/06/07 dj First release PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo -e "hello world! \a \n" exit 0

#! to declare the shell version used by this script.
Notes include:

  1. Content and function of script;
  2. Version information of script;
  3. Script author and contact information;
  4. The copyright life style of script;
  5. Date of establishment of documents;
  6. History of scripts;
  7. The special commands in the script are executed in the way of absolute path, and sufficient comments are given;
  8. The environment variables required for the script to run are pre declared and set.
chmod a+x hello.sh Add x permission to all three, which refers to the owner of the file, the group to which the file belongs, and others Example 2: interaction with users
cat showname.sh //Output: #!bin/bash #Program: # User inputs his first name and last name. Program shows his full name. #History: #2020/06/08 dj First relese PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH read -p "Please input your first name:" firstname read -p "Please input your last name:" lastname echo -e "\nYour full name is: $ $"
Example 3: file name changing with date
cat create_3_filename.sh //Output: #!/bin/bash #Program: # Program create three files,which named by user's input and date command. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH # 1.get file name from user echo -e "I will use 'touch' command to create 3 files." read -p "Please input your file name:" fileuser # 2. filename=${fileuser:-"filename"} # 3.get file name from date date1=$(date --date='2 days ago' +%Y%m%d) date2=$(date --date='1 days ago' +%Y%m%d) date3=$(date +%Y%m%d) file1=$$ file2=$$ file3=$$ # 4.create file touch "$" touch "$" touch "$"

Please note that there must be a space between '2 days ago' and% Y%m%d of date1 = $(date -- date ='2 days ago '+% Y%m%d)!

[dj@study bin]$ sh create_3_filename.sh I will use 'touch' command to create 3 files. Please input your file name:djTest [dj@study bin]$ ll Total dosage 12 -Rw-rw-r --. 1 dj DJ 674 June 8 11:13 create_3_filename.sh -Rw-rw-r --. 1 dj DJ 0 June 8 11:10 djTest -Rw-rw-r --. 1 dj DJ 0 June 8 11:13 djTest20200606 you can see three new files here -Rw-rw-r --. 1 dj DJ 0 June 8 11:13 djTest20200607 you can see three new files here -Rw-rw-r --. 1 dj DJ 0 June 8 11:13 djTest20200608 you can see three new files here -Rwxrwxr-x.1 dj DJ 224 June 7 20:14 hello.sh -Rw-rw-r --. 1 dj DJ 370 June 8 10:57 showname.sh Example 4: find the product of two integers (only integers can be calculated in bash shell)
cat multiplying.sh //Output: #!/bin/bash # Program: # User inputs 2 integer numbers;program will cross these two numbers. # History: # 2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo -e "You SHOULD input 2 numbers,I will multiplying them!\n" read -p "first number:" firstnumber read -p "second number:" secondnumber total=$(($*$)) declare -i total1=$*$ echo -e "\nThe result of $ x $ is ==> $" echo -e "\nThe result of $ x $ is ==> $"

Command execution:

[dj@study bin]$ sh multiplying.sh You SHOULD input 2 numbers,I will multiplying them! first number:10 second number:6 The result of 10 x 6 is ==> 60 The result of 10 x 6 is ==> 60

It shows that both calculation methods are available:

total=$(($*$)) declare -i total1=$*$

recommend:

var = $((operation content))

With the help of bc command, the number with decimal point is calculated.

echo "123.123*2.3"|bc Output: 283.182 Example 5: using bc to find Pi
cat cal_pi.sh //Output: #!/bin/bash #Program: # User input a scale number to calculate pi number. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo -e "This program will calculate pi value.\n" echo -e "You should input a float number to calculate pi value.\n" read -p "The scale number (10~10000) ? " checking num=${checking:-"10"} echo -e "Starting calculate pi value. Be paient." time echo "scale=$;4*a(1)" | bc -lq

Where 4*a(1) is a function provided by bc to calculate Pi. Operation:

[dj@study bin]$ sh cal_pi.sh This program will calculate pi value. You should input a float number to calculate pi value. The scale number (10~10000) ? 10 Starting calculate pi value. Be paient. 3.1415926532 real 0m0.004s user 0m0.002s sys 0m0.002s

12.2.2 differences in script execution (source, sh script,. / script)

Using direct execution to execute scripts, absolute PATH, relative PATH, $, bash, sh, the script will use a new bash environment to execute commands in the script. Is executed in a subprocess. After execution, all data is deleted and cannot be read in the parent process.

Use source to execute the script in the parent process. After execution, the data remains in the parent process. Therefore, in order for the updated ~ /. bashrc to take effect, you need to use source ~/.bashrc instead of bash ~/.bashrc.

12.3 make good use of judgment

$? && ||

12.3.1 test function by test command

test is used to detect some files or related properties on the system.

test -e /dj check whether the file or directory exists, and no information will be displayed after execution

Use $? Or & & or|to show the results:

Test - E / DJ & & echo "exist" | | echo "not exist" if the file exists, continue to execute & & the one on the right, otherwise, ignore & & directly execute the one on the right

As for the parameters of test, there is a huge table on page 396 of the book, which can be referred to.
It is commonly used as follows:

Test parameters significance -e See if the file exists -f See if the file exists and is a file -d See if the file exists and is a directory
cat file_perm.sh //Output: #!/bin/bash #Program: # User input a filename,program will check the following: # 1)exist? 2)file/directory? 3)file permissions #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/.bashrc export PATH # 1. Check whether the content entered by the user is empty echo -e "Please input a filename,I will check the filename's type and permission.\n\n" read -p "Input a filename:" filename test -z $ && echo "You MUST input a filename." && exit 0 # 2. Judge whether the file exists, and exit if it does not exist test ! -e $ && echo "The filename '$' DO NOT EXIST" && exit 0 # 3. Determine whether it is a file or a directory; determine permissions test -f $ && filetype="regular file" test -d $ && filetype="directory" test -r $ && perm="readable" test -w $ && perm="$ writable" test -x $ && perm="$ executable" # 4. Output judgment results echo "The filename: $ is a $" echo "And the permissions for you are:$"

Execution result:

[dj@study bin]$ sh file_perm.sh Please input a filename,I will check the filename's type and permission. Input a filename:/home/dj The filename: /home/dj is a directory And the permissions for you are:readable writable executable

12.3.2 using the judgment symbol []

Determine if the variable $ is empty: [- Z "$"]; echo $? In particular, note that there is a space on the left side of the bracket [there is a space on the right side, and there is a space on the left side of the bracket], otherwise an error is reported Output: 1 Example 6: use [] for judgment
cat ans_yn.sh //Output: #!/bin/bash #Program: # This program shows the user's choice #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH read -p "Please input (Y/N):" yn [ "$" == "Y" -o "$" == "y" ] && echo "OK,continue" && exit 0 [ "$" == "N" -o "$" == "n" ] && echo "Oh,interrupt!" && exit 0 echo "I donot know what your choice is" && exit 0

Execution result:

[dj@study bin]$ sh ans_yn.sh Please input (Y/N): I donot know what your choice is [dj@study bin]$ sh ans_yn.sh Please input (Y/N):y OK,continue [dj@study bin]$ sh ans_yn.sh Please input (Y/N):N Oh,interrupt!

12.3.3 default variables for shell scripts ($0, $1...)

/path/to/scriptname opt1 opt2 opt3 $0 $1 $2 $3
Special variable significance $# Number of subsequent parameters, not 3 here $@ "$1" "$2" "$3", each variable is independent $* "$1c"c", c is the separator character, and the default is space Example 7: output the parameter information of the current execution command
cat show_paras.sh //Output: #!/bin/bash #Program: # Program shows the script name,parameters... #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo "The script name is ===> $" echo "Total parameter number is ===> $#" [ "$#" -lt 2 ] && echo "The number of parameters is less than 2. Stop here." && exit 0 echo "Your whole parameters is ===> '$@'" echo "The 1st parameter ===> $" echo "The 2nd parameter ===> $"

Implementation:

sh show_paras.sh theone thetwo thethree The script name is ===> show_paras.sh Total parameter number is ===> 3 Your whole parameters is ===> 'theone thetwo thethree' The 1st parameter ===> theone The 2nd parameter ===> thetwo
Example 8: use of shift, remove the first few parameters
cat shift_paras.sh #!/bin/bash #Program: # Program shows the effect of shift function. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo "Total parameter number is ==> $#" echo "Your whole parameter is ==> '$@'" shift echo "Total parameter number is ==> $#" echo "Your whole parameter is ==> '$@'" shift 3 echo "Total parameter number is ==> $#" echo "Your whole parameter is ==> '$@'"

Implementation:

[dj@study bin]$ sh shift_paras.sh theone thetwo thethree thefour thefive thesix Total parameter number is ==> 6 Your whole parameter is ==> 'theone thetwo thethree thefour thefive thesix' Total parameter number is ==> 5 Your whole parameter is ==> 'thetwo thethree thefour thefive thesix' Total parameter number is ==> 2 Your whole parameter is ==> 'thefive thesix'

12.4 condition judgment

if then

12.4.1 using if then

Simple version:

if [conditional judgment]; then When the condition judgment formula is established, the content of the order work; fi Example 9: use if then rewrite example 6
cat ans_yn-2.sh //Output: #!/bin/bash #Program: # This program shows the user's choice #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH read -p "Please input (Y/N):" yn if [ "$" == "Y" ] || [ "$" == "y" ]; then echo "OK,continue" exit 0 fi if [ "$" == "N" ] || [ "$" == "n" ]; then echo "Oh,interrupt!" exit 0 fi echo "I donot know what your choice is" && exit 0

Complex version:

if [conditional judgment]; then When the condition judgment formula is established, the content of the order work; else When the condition judgment formula is not tenable, the content of the order work; fi

More complex version:

if [conditional 1]; then When the condition judgment formula 1 is established, the content of the command work; elif [conditional judgment 2]; then When condition judgment 2 is established, the content of the order work; else When the condition judgment formula 1 and 2 are not tenable, the content of the order work is carried out; fi Example 10: use if elif… then rewrite example 6
cat ans_yn-3.sh #!/bin/bash #Program: # This program shows the user's choice #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH read -p "Please input (Y/N):" yn if [ "$" == "Y" ] || [ "$" == "y" ]; then echo "OK,continue" exit 0 elif [ "$" == "N" ] || [ "$" == "n" ]; then echo "Oh,interrupt!" exit 0 else echo "I donot know what your choice is" && exit 0 fi
Example 11: judging additional instructions entered by the user
cat hello-2.sh //Output: #!/bin/bash #Program: # This program check $1 is equal to "hello" #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH if [ "$" == "hello" ];then echo "Hello,how are you?" elif [ "$" == "" ];then echo "You MUST input parameters,ex> { $ someword }" else echo "The only parameter is 'hello',ex> {$ hello}" fi
Example 12: check whether your host has opened the main network service port

Command netstat to query the network service port opened by the current host.
Each port has its own specific network services, common ports and related network services:

port service 80 WWW 22 ssh 21 ftp 25 mail 111 RPC (remote procedure call) 631 CUPS (printing service function)
netstat -tuln //Output: Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp6 0 0 ::1:631 :::* LISTEN tcp6 0 0 ::1:25 :::* LISTEN tcp6 0 0 :::111 :::* LISTEN tcp6 0 0 :::22 :::* LISTEN udp 0 0 0.0.0.0:908 0.0.0.0:* udp 0 0 0.0.0.0:44545 0.0.0.0:* udp 0 0 192.168.122.1:53 0.0.0.0:* udp 0 0 0.0.0.0:67 0.0.0.0:* udp 0 0 0.0.0.0:111 0.0.0.0:* udp 0 0 0.0.0.0:5353 0.0.0.0:* udp6 0 0 :::908 :::* udp6 0 0 :::111 :::*
cat netstat.sh //Output: #!/bin/bash #Program: # Using netstat and grep to detect WWW,SSH,FTP and Mail service. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH # 1. echo "Now,I will detect your linux server's services!" echo -e "The www,ftp,ssh,mail(smtp) will be detect!\n" # 2. testfile=/dev/shm/netstat_checking.txt netstat -tuln > $ testing=$(grep ":80" ${testfile}) if [ "$" != "" ];then echo "WWW is running in your system." fi testing=$(grep ":22" ${testfile}) if [ "$"!="" ];then echo "SSH is running in your system." fi testing=$(grep ":21" ${testfile}) if [ "$"!="" ];then echo "FTP is running in your system." fi testing=$(grep ":25" ${testfile}) if [ "$"!="" ];then echo "MAIL is running in your system." fi

Note: if ["$"! = "]; there is a space between if and [in then, which cannot be missing.
Implementation:

[dj@study bin]$ sh netstat.sh Now,I will detect your linux server's services! The www,ftp,ssh,mail(smtp) will be detect! SSH is running in your system. FTP is running in your system. MAIL is running in your system.

12.4.2 using case esac judgment

case $variable name in "First variable content") Program segment ;; "Second variable content") Program segment ;; *) Program segment ;; esac

*Indicates all other situations.

12.4.3 using function function

function fname(){ Program segment } Example 13: print user selection, one, two, three
cat show123.sh //Output: #!/bin/bash #Program: # Use function to repeat information. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH function printit(){ echo -n "Your choice is " } echo "This program will print your selection!" case $ in "one") printit;echo $ | tr 'a-z' 'A-Z' ;; "two") printit;echo $ | tr 'a-z' 'A-Z' ;; "three") printit;echo $ | tr 'a-z' 'A-Z' ;; *) echo "Usage $ " ;; esac

function also has $0 $1 $2 in it. This kind of variable is easy to confuse with $0 $1 $2 in shell script

12.5 loop

12.5.1 while do done, until do done

while [ condition ] do Procedure paragraph done until [ condition ] do Procedure paragraph done Example 14: loop until the user enters the correct character

Use while:

cat yes_to_stop.sh //Output: #!/bin/bash #Program: # Repeat question until user input correct answer. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH while [ "$" != "yes" -a "$" != "YES" ] do read -p "Please input yes/YES to stop this program: " yn done echo "OK! you input the correct answer."

Use until:

cat yes_to_stop-2.sh //Output: #!/bin/bash #Program: # Repeat question until user input correct answer. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH while [ "$" == "yes" -a "$" == "YES" ] Just change this to==that will do do read -p "Please input yes/YES to stop this program: " yn done echo "OK! you input the correct answer."
Example 15: use cycle to calculate 1 + 2 + 3 + +100
cat cal_1_100.sh //Output: #!/bin/bash #Program: # Use loop to calculate "1+2+3+4+5+...+100" result. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH s=0 i=0 while [ "$" != "100" ] do i=$(($i + 1)) s=$(($s+$i)) done echo "The result of '1+2+3+...+100' is ==> $s"

Implementation:

sh cal_1_100.sh //Output: The result of '1+2+3+...+100' is ==> 5050
Example 16: the maximum number n in example 15 is specified by the user, 1 + 2 + 3 + +user_input
cat cal_1_100.sh //Output: #!/bin/bash #Program: # User input n,I will use loop to calculate "1+2+3+4+5+...+n" result. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH read -p "Please input n:" n s=0 i=0 while [ "$" != "$" ] do i=$(($i + 1)) s=$(($s+$i)) done echo "The result of '1+2+3+...+ '$ is ==> $s"

Implementation:

sh cal_1_100.sh Please input n:10 The result of '1+2+3+...+ '10 is ==> 55

12.5.2 for… do… Do (fixed cycle)

while and until must meet a certain condition, for is known to loop several times.

for var in con1 con2 con3... do //Program segment done
Example 17: check the user's identifier and special parameters

The simple account name is identified by the cut of the pipeline command, and the user's identifier and special parameters are checked by id.

cat userid.sh //Output: #!/bin/bash #Program: # Use id,finger command to check system account's information. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH users=$(cut -d ':' -f1 /etc/passwd) for username in $ do id $ done
sh userid.sh //Output: uid=0(root) gid=0(root) group=0(root) uid=1(bin) gid=1(bin) group=1(bin) uid=2(daemon) gid=2(daemon) group=2(daemon) uid=3(adm) gid=4(adm) group=4(adm) ... uid=38(ntp) gid=38(ntp) group=38(ntp) uid=72(tcpdump) gid=72(tcpdump) group=72(tcpdump) uid=1000(dj) gid=1000(dj) group=1000(dj),10(wheel)
Example 18: check whether 100 hosts of 192.168.1.1-192.168.1.100 are connected with their own hosts at present
cat pingip.sh //Output: #!/bin/bash #Program: # Use ping command to check the network's PC state. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH network="192.168.1" for sitenu in $(seq 1 100) do ping -c 1 -w 1 $.$ &> /dev/null && result=0 || result=1 if [ "$" == 0 ];then echo "Server $.$ is UP." else echo "Server $.$ is DOWN." fi done

Here, $(seq 1 100) can be replaced with . Similarly, a-g characters are output consecutively, echo .

Example 19: the user enters a directory, and the program finds out the permissions of all file names in the directory
cat dir_perm.sh //Output: #!/bin/bash #Program: # User input dir name,I find the permission of files. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH # 1. read -p "Please input a directory: " dir if [ "$" == "" -o ! -d "$" ];then echo "The $ is NOT exist in your system." exit 1 fi # 2. filelist=$(ls ${dir}) for filename in $ do perm="" test -r "$/$" && perm="$ readable" test -w "$/$" && perm="$ writable" test -x "$/$" && perm="$ executable" echo "The file $/$'s permission is $" done

Implementation:

sh dir_perm.sh //Output: Please input a directory: /home/dj The file /home/dj/a2's permission is readable writable executable The file /home/dj/bin's permission is readable writable executable The file /home/dj/catfile's permission is readable writable The file /home/dj/homefile's permission is readable writable The file /home/dj/last.list's permission is readable writable The file /home/dj/list_error's permission is readable writable The file /home/dj/list_right's permission is readable writable The file /home/dj/regular_express.txt's permission is readable writable The file /home/dj/public's permission is readable writable executable The file /home/dj/Template's permission is readable writable executable The file /home/dj/video's permission is readable writable executable The file /home/dj/picture's permission is readable writable executable The file /home/dj/file's permission is readable writable executable The file /home/dj/download's permission is readable writable executable The file /home/dj/music's permission is readable writable executable The file /home/dj/desktop's permission is readable writable executable

12.5.3 for… do… Numerical processing of done

for ((initial value; limit value; assignment operation)) do Program segment done Example 20: the same as example 16, the maximum number n in example 15 is specified by the user, 1 + 2 + 3 + +user_input
cat cal_1_100-2.sh //Output: #!/bin/bash #Program: # Try to calculate 1+2+3+...+$ #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH read -p "Please input a number, I will count for 1+2+3+...+your_input:" nu s=0 for (( i=1;i<=$;i=i+1 )) do s=$(($+$)) done echo "The result of '1+2+3+...+$' is ==> $"

Implementation:

sh cal_1_100-2.sh //Output: Please input a number, I will count for 1+2+3+...+your_input:10 The result of '1+2+3+...+10' is ==> 55

12.5.4 experiment with random numbers and arrays

Some of the logic in this is not smooth, so I will continue to learn.

cat what_to_eat.sh //Output: #!/bin/bash #Program: # Try do tell you what you may eat. #History: #2020/06/08 dj First release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH eat[1]="maidangdanghanbao1" eat[2]="maidangdanghanbao2" eat[3]="maidangdanghanbao3" eat[4]="maidangdanghanbao4" eat[5]="maidangdanghanbao5" eat[6]="maidangdanghanbao6" eatnum=6 eated=0 while [ "$" -lt 3 ];do check=$(( $ * $ / 32767 + 1)) mycheck=0 if [ "$" -ge 1 ];then for i in $(seq 1 ${eated}) do if [ $ == $check ];then mycheck=1 fi done fi if [ $ == 0 ];then echo "you may eat $]}" eated=$(( $ + 1 )) eatedcon[$]=$ fi done

Operation:

sh what_to_eat.sh you may eat maidangdanghanbao1 you may eat maidangdanghanbao4 you may eat maidangdanghanbao5

12.6 script tracking and debugging

sh [-nvx] scripts.sh -n Don't execute scripts, just check for syntax problems -v Before executing the script, output the contents of the script file to the screen -x Display the script content used to the screen (quite useful) sh -x scripts.sh Procedural debug

12 June 2020, 01:19 | Views: 2547

Add new comment

For adding a comment, please log in
or create account

0 comments