Linux shell script without interaction

Here Document Free interaction

Use I/O redirection to provide a command list to an interactive program or command, such as the ftp, cat, or read commands.
is an alternative to standard input

It can help script developers not to use temporary files to build input information, but to directly produce a “file” on the spot and use it as the standard input of “command”.

Here Document can also be used with non-interactive programs and commands.

Grammar format

command <<tag
...
Content # between the tags is the incoming content
...
tag

Notes

Mark can use any legal character (usually EOF)
The end mark must be written in the top case, and there cannot be any characters in front of it
There must also not be any characters (including spaces) after the closing tag
Spaces before and after the opening tag are omitted

Realize the statistics of the number of lines without interaction, place the content to be counted between the markers “EOF”, and directly pass the content to wc -l for statistics

[root@xue xue] wc -l <<EOF
> A
> B
> C
> D
> E
> EOF
5

Receive and print the input through the read command, the input value is the part between the two EOF markers, as the value of the variable i

Note The read command can only get the content of the first line and assign it to a variable.

[root@xue xue] read i << EOF
> hello world
> EOF

[root@xue xue] echo $i
hello world

Set a password for the user through passwd

passwd zhangsan << EOF
>abc123 #Enter password
>abc123 #confirm password
>EOF

EOF cat writes a file once, replacing vim interaction

cat originally output the content of EOF to the screen, now it is redirected to the test.sh file to complete the file writing

[root@xue xue] cat << EOF >test.sh #cat > test.sh <<EOF Both ways are fine
> #!/bin/bash
> #test shell script
> cd /boot/
> ls -l vm*
> EOF

EOF | tee directly output the content of the file after inputting the file without interaction for easy inspection

tee implements both standard output and redirected output

[root@xue xue] cat <<EOF | tee abc.txt
> 123
> abc
> 456
> def
> 789
> EOF
123
abc
456
def
789

Support variable substitution

EOF can also be used in scripts and supports substitution variables

#!/bin/bash
file="EOF1.txt"
i="school"
cat > $file <<EOF
I am going to $i
EOF
cat EOF1.txt

Assign the value to the variable as a whole, and then print the variable value through the echo command

#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<EOF
This is Line 1.
Today is Monday.
$var
EOF
)

echo "$myvar"
#echo $myvar Without double quotes will cause the newline character to become a space and output on the same line. Add double quotes to keep the output formatted correctly

[root@xue xue] sh eo.sh
This is Line 1.
Today is Monday.
Great! I am going to school!

Turn off the function of variable substitution, output according to the original character, without any modification or replacement

Useful when using one script to write another script EOF

#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<'EOF' #? Add single quotes to the EOF mark to turn off variable substitution
This is Line 1.
Today is Monday.
$var
EOF
)
echo $myvar


[root@xue xue] sh eo.sh
This is Line 1.
Today is Monday.
$var

Remove the TAB characters before each line

-EOF can suppress the first TAB of each line but cannot work on spaces

#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<-'EOF' #? Add "-" before the mark to suppress the first TAB of each line
            This is Line 1.
        Today is Monday.
    $var
EOF
)
echo $myvar

Multi-line comments

Bash’s default comment is “#”, which only supports single-line comments; the introduction of Here Document solves the problem of multi-line comments.
“:” represents an empty command that does nothing. The content in the middle marked area will not be executed and will be ignored by bash, so the effect of batch comments can be achieved.

: <<EOF
...
Commands between ... # are commented
...
EOF
#!/bin/bash
var="Great! I am going to school!"
: <<-EOF #Multi-line comment, the Here Document tag content at the beginning of ":" will not be executed
            This is Line 1.
        Today is Monday.
    $var
EOF
echo "abc"

[root@xue xue] sh eo.sh
abc

Expect

A tool based on the tcl language, which is often used for automated control and testing, and solves interaction-related problems in shell scripts.

Need to install package expect

rpm -q expect
rpm -q tcl
yum install -y expect

Basic commands

1. Script interpreter

The file is first introduced in the expect script, indicating which shell is used.

#!/usr/bin/expect

2. spawn
spawn is usually followed by a Linux execution command, which means opening a session, starting a process, and tracking subsequent interaction information.

spawn passwd root

3. expect
Determine whether the specified string is included in the last output result, and if so, return immediately, otherwise wait for the timeout and return;
Can only capture the output of processes started by spawn;
Used to receive the output after the command is executed, and then match the expected string

4. send
Send a character string to the process to simulate user input; this command cannot automatically return and line feed, generally add \r (carriage return) or \

Method 1

expect "password" {send "abc123\r"}
#The send part of the same line must have {}

Method 2

 expect "password"
send "abc123\r"
#Newline send part does not need to have {}

Method 3
expect supports multiple branches

expect
{
"Password 1" {send "abc123\r"}
"Password 2" {send "123456\r"}
"Password 3" {send "123123\r"}
}
#As long as one of the conditions is matched, execute the corresponding send statement and exit the expect statement

5. Terminator

expect eof

Indicates that the interaction is over, wait for the execution to end, and return to the original user, corresponding to spawn.
For example, if you switch to the root user, the expect script waits for 10s by default. After the command is executed, it stays for 10s by default and then automatically switches back to the original user.

interact

Keep the interactive state after the execution is completed, and give the control to the console, it will stay in the target terminal and will not return to the original terminal. At this time, it can be operated manually. The command after the interact does not work, such as adding exit after the interact, does not exit the root user. And if there is no interact, it will exit after the login is completed instead of staying on the remote terminal.
Using interact will stay in the terminal and will not return to the original terminal. For example, if you switch to the root user, you will always be in the root user state; for example, if you ssh to another server, you will always be in the terminal of the target server without switching back to the original server. .

Note: expect eof and interact can only choose one or the other.

6.set
The default timeout time of expect is 10 seconds. The session timeout time can be set through the set command. If the timeout time is not limited, it should be set to -1.

set timeout 30

7.exp_continue
exp_continue is appended to an expect judgment item, so that after the item is matched, it can continue to match other items in the expect judgment statement. exp_continue is similar to the continue statement in control statements. Indicates that expect is allowed to continue executing instructions downward.

The following example will check whether yes/no or *password exists in the interactive output. If it matches yes/no, it will output yes and execute the judgment again; if it matches *password, it will output abc123 and end the expect statement.

To simulate SSH login for the first time, you need to enter yes to obtain the secret key and enter the password, and only need to enter the password later.

expect {
    "(yes/no)" {send "yes\r"; exp_continue;}
    #exp_continue Output yes after the condition matching is met, and continue to judge the following conditions without exiting
    "*password" {set timeout 300; send "abc123\r";}
}

Attention

When using exp_continue, if you track a command like passwd that ends the process after entering a password, do not add expect eof in addition to expect{}
Because after the spawn process ends, eof will be sent to expect by default, which will cause the subsequent expect eof to report an error

8. send_user
send_user means echo command, which is equivalent to echo

9. Receive parameters
The expect script can accept arguments passed from the bash command line, obtained using [lindex $argv n]. Among them, n starts from 0, respectively representing the first, second, third…. parameters.

set hostname [lindex $argv 0] #equivalent to hostname=$1
set password [lindex $argv 1] #equivalent to password=$2

expect is executed directly, you need to use the expect command to execute the script

Or chmod + x, execute with ./sh

su switch user

#!/usr/bin/expect
#Set timeout
set timeout 5
#parameters passed in
set username [lindex $argv 0]
set password [lindex $argv 1]
# start tracking command
spawn su $username
# Interaction-free execution, capturing information and matching
expect "password"
send "$password\r"
expect "*]" #Display after entering the correct password [root@xue xue]# match *]
send_user "ok"

interact #Give control to the console
#expect eof #Exit to the original user xue after a timeout of 5 seconds
adduser wolong #create user
echo abc123 | passwd --stdin wolong

chmod +x exp.sh
./exp.sh wolong abc123
#sh exp.sh execution will report an error #!/usr/bin/expect

Embedded execution mode, run expect in bash. Create a user and set a password

It is generally not recommended to use the embedded execution mode for interactive commands that switch environments, such as ssh and su.

#!/bin/bash
user=$1
password=$2
#Non-interactive commands are placed outside expect
useradd $user
#Start swap-free execution
/usr/bin/expect <<-EOF #expect start flag Pass the following EOF interaction-free to /usr/bin/expect for execution
spawn passwd $user #Open a process tracking passwd command, expect can only capture the process information

expect "new*"
send "${password}\r"
expect "re*"
send "${password}\r"
expect eof
EOF

Implement ssh automatic login

#!/usr/bin/expect
set timeout 5
set hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh $hostname
expect {
    "Connection refused" {send_user "ssh access denied\
"} #Connection failure, such as the other party's ssh service is closed
    "No route to host" {send_user "The host name/IP is incorrect\
"} #The server cannot be found, such as the input IP address is incorrect
    "(yes/no)" {send "yes\r";exp_continue}
    #You need to enter yes to download the key for the first connection. In order to continue to enter the password in the next step, you need to write exp_continue. It is better to exit directly after satisfying this one and no longer judge.
    "password:" {send "$password\r"}
}

interact
Commands after exit #interact do not work

Create disk partition and format

1. The traditional way of writing echo to pass parameters to fdisk without interactive execution

#!/bin/bash
NEWDEV=`ls /dev/sd*|grep -o 'sd[b-z]'|uniq`
for VAR in $NEWDEV
do
    echo -e "n\
p\
\
\
\
w\
" | fdisk /dev/$VAR &> /dev/null
done

mkfs.xfs /dev/${VAR}"1" &> /dev/null

Two other ways of writing the echo part

echo -e "n\
p\
\
\
\
w\
" > fd.txt
fdisk /dev/$VAR < fd.txt
echo "n
    p
    
    
    
    w" | fdisk /dev/$VAR

2. Expect writing method Output the corresponding characters according to the obtained text through expect and send

Use expect to implement fdisk /dev/sdb to create partitions without interaction

Requires a one-time creation

A 10G /dev/sdb1 common partition

A 2G /dev/sdb2 swap partition

A 6G /dev/sdb5 logical partition

#!/usr/bin/expect
set timeout 5

spawn fdisk /dev/sdb
expect "command" {send "n\r"}
expect "Partition type" {send "p\r"}
expect "partition number" {send "\r"}
expect "start sector" {send "\r"}
expect "Last sector" {send " + 10G\r"}
expect "already set to Linux type" {send_user "primary partition 10G set complete"}

expect "command" {send "n\r"}
expect "Partition type" {send "p\r"}
expect "partition number" {send "\r"}
expect "start sector" {send "\r"}
expect "Last sector" {send " + 2G\r"}
expect "set to Linux type" {send "t\r"}
expect "partition number" {send "2\r"}
expect "Hex" {send "82\r"}
expect "The type of partition "Linux" has been changed to "Linux swap" {send_user "swap partition 2G setup is complete"}

expect "command" {send "n\r"}
expect "Partition type" {send "e\r"}
expect "partition number" {send "\r"}
expect "start sector" {send "\r"}
expect "Last sector" {send " + 6G\r"}
expect "is set to Extended type" {send "n\r"}
expect "Partition type" {send "l\r"}
expect "start sector" {send "\r"}
expect "Last sector" {send "\r"}
expect "already set to Linux type" {send "w\r";send_user "extended partition 6G set complete"}


#expect eof
interact