Shell 练习题(三)

1.软链接和硬链接有什么区别

软链接是文件名的链接,也可以驻留在不同的文件名中; 但硬链接链接到文件的inode,并且必须与文件的文件系统相同。删除原始文件会使软链接处于非活动状态(断开链接),但不会影响硬链接(硬链接仍将访问该文件的副本)

默认情况下,ln命令产生硬链接
硬链接指向一个 inode 节点,而软链接则是创建一个新的 inode 节点。

硬链接:
①不允许给目录创建硬链接。
②只有在同一文件系统中的文件之间才能创建链接。 即不同硬盘分区上的两个文件之间不能够建立硬链接。这是因为硬链接是通过结点指向原始文件的,而文件的i-结点在不同的文件系统中可能会不同。
Linux操作可以对目录进行硬链接? 不可以

软链接:
软连接就相当于我们win中的快捷方式即如果你软连接一个目录只是一个目录的快捷方式到指定位置,操作系统找这个快捷方式会直接找到真实目录下的文件
ln -s

2.判断一文件是不是字符设备文件,如果是将其拷贝到 /dev 目录下

#!/bin/bash
read -p “Input file name:” FILENAME
if [ -c “$FILENAME];then
cp $FILENAME /dev
fi

[ 条件测试

[ -d DIR ]         如果DIR存在并且是一个目录则为真
[ -f FILE ]        如果FILE存在且是一个普通文件则为真
[ -z STRING ]      如果STRING的长度为零则为真
[ -n STRING ]      如果STRING的长度非零则为真
[ STRING1 = STRING2 ]    如果两个字符串相同则为真 
[ STRING1 != STRING2 ]   如果字符串不相同则为真
[ ARG1 OP ARG2]    ARG1和ARG2应该是整数或者取值为整数的变量
OP是-eq(等于) -ne(不等于) -lt(小于) -le(小于等于) -gt(大于) -ge(大于等于)

带与、或、非的测试命令
EXPR可以是上表中的任意一种测试条件
[ ! EXPR ]
[ EXPR1 -a EXPR2]   -a表示逻辑与
[ EXPR1 -o EXPR2]   -o表示逻辑或
例如:
$ VAR=abc
$ [ -d Desktop -a "$VAR" = 'abc' ]    ❤
$ echo $?
0
注意:作为一种好的Shell编程习惯,应该总是把变量取值放在双引号之中。 避免因变量事先没有定义,则被Shell展开为空字符串而造成测试条件的语法错误


配合if语句

if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi

运算符
1.关系运算符
在这里插入图片描述
2.逻辑运算符
在这里插入图片描述

3.字符串运算符
在这里插入图片描述
[ = ] 是字符串比较, [ == ]是数值比较

在这里插入图片描述

扫描二维码关注公众号,回复: 11702795 查看本文章

4.文件测试运算符
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

3.对文件test.txt找出行尾结束为小数点的行,并统计行数

grep -n '\.$' test.txt | wc -l

[root@aliyun ~]# cat test.txt 
My name is fruit,
I am now working at HS in Hangzhou as a intern.
I am so sad failed in the Sangfor final test,
but I got the green card about autumn recruitment in 2020.
I still have a chance to try it!

Break a leg in 2020.
[root@aliyun ~]# grep -n '\.$'  test.txt
2:I am now working at HS in Hangzhou as a intern.
4:but I got the green card about autumn recruitment in 2020.
7:Break a leg in 2020.
[root@aliyun ~]# grep -n '\.$'  test.txt | wc -l
3

在这里插入图片描述

涉及知识点
正则表达式

^     匹配行首的位置         ^Content匹配位于一行开头的Content
$     匹配行末的位置         ;$匹配位于一行结尾的;号,^$匹配空行
[^ ]       位于[]括号内的开头,匹配除括号中的字符之外的任意一个字符    [^xy]匹配除xy之外的任一字符

原文链接:https://blog.csdn.net/qq_39578545/article/details/104902554

grep

-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行
-w : 作为整个单词进行匹配
-o : 只显示匹配内容

空白行:
grep -n '^$' test.txt

给定一个文件找到包含单词"ABC”的行数。
grep -c "ABC" file1

wc

wc 有四个参数可选,分别是l,c,m,w
wc -l filename 报告行数
wc -c filename 报告字节数
wc -m filename 报告字符数
wc -w filename 报告单词数 

对文件test.txt统计行数
wc -l test.txt

统计当前文件夹下的文件占用的字节数
ls -l | wc -c

统计当前目录下的文件数
ls -l | wc -l

4.写一个脚本,实现批量添加20个用户,密码为user后跟5个随机字符

    for i in {
    
    1..20}
    do 
       username=user$i
       passwd="user`cat /dev/random | head -1 | md5sum | head -c 5`"
       useradd $username 
       echo "$passwd" | passwd --stdin $username
       echo "$username--$passwd" >> user.txt
    done

生成随机字符方法:
cat /dev/random | head -1 | md5sum | head -c 5

非交互式设置密码
echo “新密码”|passwd --stdin 用户名
[root@aliyun ~]# echo “qwert” | passwd --stdin hehe
更改用户 hehe 的密码 。
passwd:所有的身份验证令牌已经成功更新。

交互式设置密码:
[root@aliyun ~]# passwd hehe
Enter new password:

5.设计一个shell程序,添加一个新组为class,然后添加属于这个组的30个用户,用户名的形式为stdxx,其中xx从01到30,并设置密码为对应的stdxx

#!/bin/bash

groupadd class
for i in {
    
    class01..class30}; do
    xx=`echo $i | sed 's/class//g'`
    useradd -g class -s /bin/bash -d /home/std$xx -m std$xx
    echo -e "std$xx@123456" | passwd std$xx
    echo -e "user std$xx password is std$xx@123456" >> /root/newuser.txt
done

-s是指定用户登入后所使用的shell。默认值为/bin/bash。如果不想让用户登录系统可以用 -s /sbin/nologin.此用户就不可以登录系统。
-d:指定用户登入时的主目录,替换系统默认值/home/<用户名>
-m:自动建立用户的登入目录。

6.编写shell程序,实现自动删除30个账号的功能。账号名为std01至std30

#!/bin/bash

for i in {
    
    9901..9930}; do
    xx=`echo $i | sed 's/99//g'`
    userdel -r std$xx
done

-r代表把用户相对应的目录一并删除

7.shell中变量的含义$# $0 $@ $$ $?

$# 是传给脚本的参数个数计数
$0 是脚本本身的名字
$1 是传递给该shell脚本的第一个参数
$2 是传递给该shell脚本的第二个参数
$@ 是传给脚本的所有参数的列表
$* 是以一个单字符串显示所有向脚本传递的参数,与位置变量不同,参数可超过9个
$$ 是脚本运行的当前进程ID号
$? 是显示最后命令的退出状态,0表示没有错误,其他表示有错误

 #!/bin/sh
echo "number:$#"
echo "scname:$0"
echo "first :$1"
echo "second:$2"
echo "argume:$@"
echo "show parm list:$*"
echo "show process id:$$"
echo "show precomm stat: $?"
保存退出
 
赋予脚本执行权限
# chmod +x test
 
执行脚本
# ./test aa bb
number:2
scname:./variable
first:aa
second:bb
argume:aa bb
show parm list:aa bb
show process id:24544
show precomm stat:0

8.shell 脚本里的 特殊字符 ( ( ) ) 、 (( ))、 (())( )、``与${ }的区别

https://www.cnblogs.com/chenpython123/p/11052276.html

1. 在bash中,$( )与(反引号)都是用来作命令替换的。

命令替换与变量替换差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。
$( )与``在操作上,这两者都是达到相应的效果
在这里插入图片描述

运用:for循环打印下面这句话中字母数不大于6的单词
I am oldboy teacher welcome to oldboy training class.

#!/bin/bash
chars="i am xcn teacher welcome to xcn training class"
for n in $chars
do
  if [ ${#n} -le 6 ]
  then
    echo $n
  fi
done

2. ${ }变量替换 、 ${} 里面还可以有 #*,##*,#*,##*,% *,%% ***,配合echo

一般情况下,$var与${var}是没有区别的,但是用${ }会比较精确的界定变量名称的范围。

[root@localhost ~]# A=Linux
[root@localhost ~]# echo $AB    #表示变量AB
[root@localhost ~]# echo ${A}B    #表示变量A后连接着B
LinuxB

连接两个字符串 
V1="Hello"
V2="World"
V3=${V1}${V2}
echo $V3
输出:HelloWorld

截取变量的部分

file=/dir1/dir2/dir3/my.file.txt
可以用${ }分别替换得到不同的值:
${
    
    file#*/}:   删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${
    
    file##*/}: 删掉最后一个 /  及其左边的字符串:my.file.txt
${
    
    file#*.}:    删掉第一个 .  及其左边的字符串:file.txt
${
    
    file##*.}:  删掉最后一个 .  及其左边的字符串:txt
${file%/*}:    删掉最后一个  /  及其右边的字符串:/dir1/dir2/dir3
${file%%/*}: 删掉第一个 /  及其右边的字符串:(空值)
${file%.*}:    删掉最后一个  .  及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}: 删掉第一个  .   及其右边的字符串:/dir1/dir2/dir3/my

记忆的方法为:
# 是 去掉左边(键盘上#在 $ 的左边)
%是去掉右边(键盘上% 在$ 的右边)
单一符号是最小匹配;两个符号是最大匹配

取子串及替换

命令                                    解释                              结果
${file:0:5}               提取最左边的 5 个字节                /dir1
${file:5:5}               提取第 5 个字节右边的连续 5 个字节         /dir2
${file/dir/path}            将第一个 dir 提换为 path              /path1/dir2/dir3/my.file.txt
${file//dir/path}        将全部 dir 提换为 path               /path1/path2/path3/my.file.txt
${#file}              获取变量长度                     27     

3. $(( )) 算数代换

$ (())中的Shell变量取值将转换成整数, 可以 整数运算、进制转换、重定义变量值

符号 功能
+ - * / 分别为加、减、乘、除
% 余数运算
& |^ ! 分别为“AND、OR、XOR、NOT”
[root@localhost ~]# echo $((2*3))
6
[root@localhost ~]# a=5;b=7;c=2
[root@localhost ~]# echo $((a+b*c))
19
[root@localhost ~]# echo $(($a+$b*$c))
19

$(( ))可以将其他进制转成十进制数显示出来。用法如下:
echo $((N#xx))
其中,N为进制,xx为该进制下某个数值,命令执行后可以得到该进制数转成十进制后的值。

[root@localhost ~]# echo $((2#110))
6
[root@localhost ~]# echo $((16#2a))
42
[root@localhost ~]# echo $((8#11))
9

(( ))重定义变量值,是 [] 数学表达式的加强版

[root@localhost ~]# a=5;b=7
[root@localhost ~]# ((a++))
[root@localhost ~]# echo $a
6
[root@localhost ~]# ((a--));echo $a
5
[root@localhost ~]# ((a<b));echo $?
0
[root@localhost ~]# ((a>b));echo $?
1

4. ${name[]} ${name[@]} ${#name[]} 区别

在linux的shell里,${name}可以表示变量,也可以表示数组。
name后面加〔〕的,一般是数组,
${name[*]}     是数组所有元素(all of the elements)
${name[@]}   是数组每一个元素(each of the elements)    ,循环数组用这个 。
${#name[*]}   是数组元素的个数,也可以写成  ${#name[@]} 
${name:-Hello} 是指,如果${name}没有赋值,那么它等于Hello,如果赋值了,就保持原值,不用管问这个Hello了。
${!array_name[@]}${!array_name[*]}     获取数组的下标。
str="  114.114.114.114 2000:192:434:234 "

#变成数组
ip_list=(${str})
for i in "${!ip_list[@]}"; do
    echo "@""$i=>${ip_list[i]}""@"
done
echo "数组个数: ${#ip_list[@]}"
echo "数组下标: ${!ip_list[@]}"

5. 单小括号 ()

命令组。括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。
  命令替换。等同于cmd,shell扫描一遍命令行,发现了 ( c m d ) 结 构 , 便 将 (cmd)结构,便将 (cmd)便(cmd)中的cmd执行一次,得到其标准输出,再将此输出放到原来命令。有些shell不支持,如tcsh。
  用于初始化数组。如:array=(a b c d) 【($str) 会把字符串按照 字段分隔符:空格、制表符、换行符 ,分割形成 数组】

9.探索文件行数

获取文件的最后一行

cat test.txt | awk 'END {print}'
head test.txt | tail -1
tail -1 test.txt

打印10 行,而无需使用尾部和头部命令。

sed "10p" test.txt

打印第十行

head -10 test.txt | tail -1  # 当文件只有9行的时候这个解法默认也会输出最后一行

正确解法:
解法一:tail
tail -n +10 filename    从第10行输出

解法二:sed
sed -n '10p' filename  打印第10行内容

解法三:awk
cat file.txt | awk 'NR==10'

awk中NR和FNR

awk可以使用自身变量NR和FNR来处理多个文件。 NR:表示awk开始执行程序后所读取的数据行数。
FNR:awk当前读取的记录数,其变量值小于等于NR(比如当读取第二个文件时,FNR是从0开始重新计数,而NR不会)。
NR==FNR:用于在读取两个或两个以上的文件时,判断是不是在读取第一个文件

10.创建一个目录,以便组中的任何人都可以创建文件并访问其中的任何人的文件,但是没有人能够删除除他自己创建的文件之外的文件。

我们可以创建一个目录,为组中的每个人提供读取和执行访问权限,并将其粘滞位设置为"t”,如下所示

mkdir direc1
chmod g + wx direc1
chmod + t direc1

11.scp 远程文件拷贝

1、从本地复制到远程 
scp local_file remote_username@remote_ip:remote_folder 
或者 
scp local_file remote_username@remote_ip:remote_file 
或者 
scp local_file remote_ip:remote_folder 
或者 
scp local_file remote_ip:remote_file 

第1,2个指定了用户名,命令执行后需要再输入密码,第1个仅指定了远程的目录,文件名字不变,第2个指定了文件名;
第3,4个没有指定用户名,命令执行后需要输入用户名和密码,第3个仅指定了远程的目录,文件名字不变,第4个指定了文件名; 

应用实例:
scp /home/space/music/1.mp3 [email protected]:/home/root/others/music 
scp /home/space/music/1.mp3 [email protected]:/home/root/others/music/001.mp3 
scp /home/space/music/1.mp3 www.runoob.com:/home/root/others/music 
scp /home/space/music/1.mp3 www.runoob.com:/home/root/others/music/001.mp3 

复制目录命令格式:
scp -r local_folder remote_username@remote_ip:remote_folder 
或者 
scp -r local_folder remote_ip:remote_folder 

第1个指定了用户名,命令执行后需要再输入密码;
第2个没有指定用户名,命令执行后需要输入用户名和密码; 

应用实例:
scp -r /home/space/music/ [email protected]:/home/root/others/ 
scp -r /home/space/music/ www.runoob.com:/home/root/others/ 
上面命令将本地 music 目录复制到远程 others 目录下。



2、从远程复制到本地
从远程复制到本地,只要将从本地复制到远程的命令的后2个参数调换顺序即可,如下实例

应用实例:
scp [email protected]:/home/root/others/music /home/space/music/1.mp3 
scp -r www.runoob.com:/home/root/others/ /home/space/music/

说明
1.如果远程服务器防火墙有为scp命令设置了指定的端口,我们需要使用 -P 参数来设置命令的端口号,命令格式如下:
#scp 命令使用端口号 4588
scp -P 4588 [email protected]:/usr/local/sin.sh /home/administrator
2.使用scp命令要确保使用的用户具有可读取远程服务器相应文件的权限,否则scp命令是无法起作用的。

12.两个整数相加

两个整数相加

方法 1 
V1=1
V2=2
let V3=$V1+$V2
echo $V3  



A=5
B=6
echo $(($A+$B)) # 方法 2
echo $[$A+$B] # 方法 3
expr $A + $B # 方法 4
echo $A+$B | bc # 方法 5
awk 'BEGIN{print '"$A"'+'"$B"'}'  # 方法 6

13.数组

定义数组 
array=("Hi" "my" "name" "is")

打印数组的第一个元素
echo ${array[0]}

输出所有数组索引
echo ${!array[@]}

移除数组中索引为 2 的元素 
unset array[2]

在数组中添加 id 为 333 的元素 
array[333]="New_element"

Shell 练习题(四) 下期再见
个人标记:shell.docx 和 119

猜你喜欢

转载自blog.csdn.net/qq_39578545/article/details/107440784