VII. non-direct reference variables:
Three methods of assigning values to standard (direct) variables are provided in shell:
1. assign values directly.
2. Store the output of a command.
3. Store the results of a certain type of computing.
However, all three methods assign values to variables with known variable names, such as name = Stephen. However, in some cases, the variable name itself is dynamic, and the variable name needs to be constructed according to the running results, and then the variable is assigned a value. Such variables are either dynamic or non-direct variables.
/> CAT> test7.sh
#! /Bin/sh
Work_dir = 'pwd'
#1. Because the variable name cannot contain a backslash, you must replace it with an underscore.
#2. The variable values of work_dir and file_count are used to construct the variable names of dynamic variables.
Work_dir = 'echo $ work_dir | SED's/\ // _/g''
File_count = 'ls | WC-l'
#3. output the values of the work_dir and file_count variables to confirm that the output result is consistent with the command name built later.
Echo "work_dir =" $ work_dir
Echo "file_count =" $ file_count
#4. use the eval command to evaluate and expand the variable names, such as $ {work_dir} and $ file_count, and replace them with their values. If you do not use the eval command, the expansion and replacement operations will not be completed. Finally, assign values to dynamic variables.
Eval base $ {work_dir }_$ file_count = $ (ls $ (PWD) | WC-l)
#5. Expand and replace the expanded part of the ECHO command with double quotation marks. Because it is in double quotation marks, only the expansion and replacement operations can be completed.
#6. Expand and replace the parameters following the echo command first to make it a $ base_root_test_1 dynamic variable, and then replace the variable itself with the value of the variable as the result output.
Eval echo "base $ {work_dir }_$ file_count =" '$ base' $ {work_dir }_$ file_count
CTRL + d
/> ../Test7.sh
Work_dir = _ root_test
File_count = 1
Base_root_test_1 = 1
8. Tips for using pipelines in a loop:
In bash shell, the last command of the pipeline is executed in the sub-shell. This means that the variable assigned in the sub-shell is invalid for the parent shell. Therefore, when we transmit the pipeline output to a loop structure and fill in the variables to be used later, there will be many problems. Once the loop is completed, the variables it depends on will no longer exist.
/> CAT> test8_1.sh
#! /Bin/sh
#1. First pass the LS-l command result to the grep command through the pipeline as the pipeline input.
#2. The grep command filters out the rows containing total, and then transmits the data to the while loop through the pipeline.
#3. The while read line command reads data from grep output. Note that while is the last command of the pipeline and will be run in the sub-shell.
Ls-L | grep-V Total | while read line
Do
#4. All variables are declared and assigned values in the while block.
All = "$ all $ line"
Echo $ line
Done
#5. since the above all variables are declared and initialized in the while, while the commands in the while are all run in the sub-shell, including the assignment of all variables, therefore, the value of this variable is not passed to the while block, because the block field command is executed in its parent shell.
Echo "All =" $ all
CTRL + d
/>./Test8_1.sh
-RW-r --. 1 Root 193 Nov 24 11: 25 out
-Rwxr-XR-X. 1 Root 284 Nov 24 10:01 test7.sh
-Rwxr-XR-X. 1 Root 108 Nov 24 test8_1.sh
All =
To solve this problem, we can first output the command results before while to a temporary file, and then use the temporary file as the redirection input for while, in this way, the while internal and external commands will be completed in the same shell.
/> CAT> test8_2.sh
#! /Bin/sh
#1. Here we have redirected the command result to a temporary file.
Ls-L | grep-V total> OUTFILE
While read line
Do
#2. The all variable is declared and assigned a value in the while block.
All = "$ all $ line"
Echo $ line
#3. Redirect the input to pass the content in the temporary file to the while loop.
Done <OUTFILE
#4. Delete the temporary file.
Rm-F OUTFILE
#5. Declare and assign all variables in the while block. The value is still valid outside the loop.
Echo "All =" $ all
CTRL + d
/>./Test8_2.sh
-RW-r --. 1 Root 0 Nov 24 12:58 OUTFILE
-Rwxr-XR-X. 1 Root 284 Nov 24 10:01 test7.sh
-Rwxr-XR-X. 1 Root 140 Nov 24 test8_2.sh
All =-rwxr-XR-X. 1 Root 284 Nov 24 10:01 test7.sh-rwxr-XR-X. 1 Root 135 Nov 24 13:16 test8_2.
The above method only solves this problem, but brings about some new problems, such as the generation of temporary files may easily lead to performance problems, when the script exits unexpectedly, it fails to promptly Delete the temporary files in use, resulting in the generation of excessive junk files. Next we will introduce another method, which will solve the problems that both methods have at the same time. This method uses the here-document method to replace the previous temporary file method.
/> CAT> test8_3.sh
#! /Bin/sh
#1. Pass the command result to a variable
OUTFILE = 'LS-L | grep-V total'
While read line
Do
All = "$ all $ line"
Echo $ line
Done <EOF
#2. Use this variable as the here document input for this loop.
$ OUTFILE
EOF
#3. The value of the variable all declared and initialized in the external output loop of the loop.
Echo "All =" $ all
CTRL + d
/>./Test8_3.sh
-Rwxr-XR-X. 1 Root 284 Nov 24 10:01 test7.sh
-Rwxr-XR-X. 1 Root 135 Nov 24 test8_3.sh
All =-rwxr-XR-X. 1 Root 284 Nov 24 10:01 test7.sh-rwxr-XR-X. 1 Root 135 Nov 24 13:16 test8_3.
IX. Self-linked script:
Generally, we use the command line option of the script to determine the different behaviors of the script and tell it how to operate it. Here we will introduce another way to accomplish similar functions, that is, to help the script determine its behavior through the soft connection name of the script.
/> CAT> test9.sh
#! /Bin/sh
#1. The basename command will strip the directory information of the script and only keep the Script Name, so that there is no difference in the execution in the relative path mode.
#2. Use the SED command to filter out the script extension.
Dowhat = 'basename $0 | SED's/\. Sh //''
#3. the case statement is used only for demonstration convenience. Therefore, the application scenario is simulated. in actual application, different operations can be performed for different branches, or initialize some variables into different values and States.
Case $ dowhat in
Test9)
Echo "I am test9.sh"
;;
Test9_1)
Echo "I am test9_1.sh ."
;;
Test9_2)
Echo "I am test9_2.sh ."
;;
*)
Echo "you are illegal link file ."
;;
Esac
CTRL + d
/> Chmod A + x test9.sh
/> Ln-s test9.sh test9_1.sh
/> Ln-s test9.sh test9_2.sh
/> Ls-l
Lrwxrwxrwx. 1 Root 8 Nov 24 test9_1.sh-> test9.sh
Lrwxrwxrwx. 1 Root 8 Nov 24 test9_2.sh-> test9.sh
-Rwxr-XR-X. 1 Root 235 Nov 24 14:35 test9.sh
/>./Test9.sh
I am test9.sh.
/>./Test9_1.sh
I am test9_1.sh.
/>./Test9_2.sh
I am test9_2.sh.
10. Tips for using the here document:
In the command line interaction mode, we usually want to directly enter more information so that the current command can complete certain automated tasks, especially for commands that support custom scripts, we can pass the script as part of the input to the command to complete the automation task.
#1. Use sqlplus to log on to the Oracle database server as a DBA.
#2. After logon, execute the Oracle scripts createmytables and createmyviews in sqlplus.
#3. Run the exit command of sqlplus to exit sqlplus. Automation is completed.
/> Sqlplus "/As sysdba" <-SQL
> @ Createmytables
> @ Createmyviews
> Exit
> SQL
11. Obtain the running duration of the process (unit: minutes ):
In the process monitoring script, we usually need to determine which performance parameters will be collected based on the Script Parameters. When these performance parameters exceed the maximum or below the minimum threshold, the monitoring script will take preset measures based on the actual situation, such as email notification and direct killing of processes. The example here is to collect the performance parameters of the process running duration.
The etime value of the ps command gives the running duration of each process. The format is as follows:
1. Minutes: seconds, for example
2. Hours: Minutes: seconds, e.g. 1:20:30
3. Days-hours: minute: seconds, for example, 2-18:20:30
The script will process the time information in these three formats at the same time and convert it to the Minutes that the process flows through.
/> CAT> test11.sh
#! /Bin/sh
#1. Use the ps command to obtain the PID, etime, and comm data of all processes.
#2. Then, use the grep command to filter and retrieve only the data records of the INIT process. Here, we can replace it with the name of the process we want to monitor as needed.
#3. The output result is usually: 1 09:42:09 init
Pid_string = 'ps-eo pid, etime, comm | grep "init" | grep-V grep'
#3. Extract the etime data from the record information, that is, the value of the second column is 09:42:09 and assigned to the exec_time variable.
Exec_time = 'echo $ pid_string | awk '{print $2 }''
#4. Obtain the number of time components of the exec_time variable. Here, there are three parts: instant: minute: Second, which is the second one in the preceding format.
Time_field_count = 'echo $ exec_time | awk-F: '{print NF }''
#5. Extract the number of minutes directly from the exec_time variable, that is, the data in the last and second columns (42 ).
Count_of_minutes = 'echo $ exec_time | awk-F: '{print $(NF-1 )}''
#6. determine the format of the time data stored in the current exec_time variable.
#7. For the first type, the number of days and hours are both 0.
#8. if it is one of the last two types, you need to continue to determine whether it is the first or the second type. If it is the second type, the hour part will not have a hyphen (-) separator to separate the number of days and hours, otherwise, you need to split the two time fields to obtain the specific number of days and hours. For the second type, the number of days is 0.
If [$ time_field_count-lt 3]; then
Count_of_hours = 0
Count_of_days = 0
Else
Count_of_hours = 'echo $ exec_time | awk-F: '{print $(NF-2 )}''
Fields = 'echo $ count_of_hours | awk-F-'{print NF }''
If [$ fields-ne 1]; then
Count_of_days = 'echo $ count_of_hours | awk-F-'{print $1 }''
Count_of_hours = 'echo $ count_of_hours | awk-F-'{print $2 }''
Else
Count_of_days = 0
Fi
Fi
#9. Before passingCodeCalculated the number of minutes that the process actually flows through.
#10. The BC command is a calculator command that can calculate the mathematical expression output by ECHO as the final numeric value.
Elapsed_minutes = 'echo "$ count_of_days * 1440 + $ count_of_hours * 60 + $ count_of_minutes" | BC'
Echo "The elapsed minutes of INIT process is" $ elapsed_minutes "Minutes ."
CTRL + d
/>./Test11.sh
The elapsed minutes of INIT process is 577 minutes.
12. simulate a simple TOP command:
The script is used to implement a very simple TOP command. For ease of demonstration, many parameters are written as hard code in the script. You can replace these parameters as needed or replace existing implementations in a more flexible way.
/> CAT> test12.sh
#! /Bin/sh
#1. Assign the title of the ps command to a variable so that the variable can be printed directly at each output.
Header = 'ps aux | head-N 1'
#2. Here is an infinite loop, equivalent to while true
#3. Clear the screen each cycle, and then print the output of the uptime command.
#4. output the title of PS.
#5. Use the SED command to delete the title line of PS to avoid its involvement in the sorting of the sort command.
#6. The sort is based on CPU % inverted sorting, sorted by owner, sorted by PID, and output the result to the head command. Only the first 20 rows of data are displayed.
#7. Refresh every 5 seconds.
While:
Do
Clear
Uptime
Echo "$ Header"
PS aux | sed-e 1D | sort-k3nr-K1, 1-K2n | head-N 20
Sleep 5
Done
CTRL + d
/>./Test12.sh
21:55:07 up, 2 users, load average: 0.00, 0.00, 0.00
User PID % CPU % mem vsz RSS tty stat Start Time Command
Root 6408 2.0 0.0 4740 932 pts/2 R + PS aux
Root 1755 0.2 2.0 96976 21260? S Nautilus
68 1195 0.0 0.4 6940 4416? SS Hald
Postfix 1399 0.0 0.2 10312 2120? S qmgr-l-t fifo-u
Postfix 6021 0.0 0.2 10244 2080? S pickup-l-t fifo-u
Root 1 0.0 0.1 2828 1364? SS/sbin/init
......