初写shell 时遇到的一些问题
一. 逐行处理文本
1.通过read命令完成.
read命令接收标准输入,或其他文件描述符的输入,得到输入后,read命令将数据放入一个标准变量中。
利用read读取文件时,每次调用read命令都会读取文件中的"一行"文本。
当文件没有可读的行时,read命令将以非零状态退出。
cat data.dat | while read line;do
echo "File:${line}"
done
while read line;do
echo "File:${line}"
done < data.dat
2.使用awk命令完成
awk是一种优良的文本处理工具,提供了极其强大的功能.
利用awk读取文件中的每行数据,并且可以对每行数据做一些处理,还可以单独处理每行数据里的每列数据.
cat data.dat | awk '{print $0}'
cat data.dat | awk 'for(i=2;i<NF;i++) {printf $i} printf "\n"}'
第1行代码输出data.dat里的每行数据,第2代码输出每行中从第2列之后的数据.
如果是单纯的数据或文本文件的按行读取和显示的话,使用awk命令比较方便.
3.使用for var in file 命令完成
for var in file 表示变量var在file中循环取值.取值的分隔符由$IFS确定.
for line in $(cat data.dat);do
echo "File:${line}"
done
# 或
for line in `cat data.dat`;do
echo "File:${line}"
done
如果输入文本每行中没有空格,则 line 在输入文本中按换行符分隔符循环取值。如果输入文本中包括空格或制表符,则不是换行读取,line 在输入文本中按空格分隔符或制表符或换行符特环取值,可以通过把 IFS 设置为换行符来达到逐行读取的功能。
IFS的默认值为:空白(包括:空格,制表符,换行符).
注意:
这段代码
path_all=""
cat test.txt | while read line
do
path_all="${path_all} ${line}"
done
echo $path_all
这段代码的本意是将test 文件中的文本按行读出并拼接成一行,但最后的输出却是空串,出现这种问题的原因和while 有关,
while循环读取文件中内容有两种写法,一种是管道符,一种是重定向,写法如下
管道符:
cat $file_name | while read line
do
#deal with line
done
重定向:
while read line
do
#deal with line
done < $file_name
这两种做法的区别在于,重定向是内建命令,而管道符是非内建命令,之所以我写的脚本出现了输出是空的问题,原因就在这里,linux执行shell时,会创建“子shell”运行shell中的命令,当运行到非内建指令时,会创建“孙shell”运行非内建指令,变量的作用于在每个shell中有效,所以,非内建指令中定义的这些变量就只能在孙shell运行,而在子shell中不生效,所以,即便在while中给path_all赋值了,子shell中也不会获取到这个值。
解决这个问题的办法有两种,如果不是必须使用管道符的方式写while循环,可以用重定向的写法,这种写法循环内的变量在子shell中是生效的,比较简便;如果非要使用管道符的方式,可以创建临时文件,用于存放孙shell中的输出。
二. 字符串截取
假设有变量 var=http://www.aaa.com/123.htm.
1. # 号截取,删除左边字符,保留右边字符。 (非贪婪匹配)
echo ${var#*/}
其中 var 是变量名,# 号是运算符,*/ 表示从左边开始删除第一个 / 号及左边的所有字符
即删除 http://
结果是 :www.aaa.com/123.htm
2. ## 号截取,删除左边字符,保留右边字符。(贪婪匹配)
echo ${var##*/}
##*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符
即删除 http://www.aaa.com/
结果是 123.htm
3. %号截取,删除右边字符,保留左边字符 (非贪婪匹配)
echo ${var%/*}
%/* 表示从右边开始,删除第一个 / 号及右边的字符
4. %% 号截取,删除右边字符,保留左边字符 (贪婪匹配)
echo ${var%%/*}
%%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符
结果是:http:
5. 从左边第几个字符开始,及字符的个数
echo ${var:0:5}
其中的 0 表示左边第一个字符开始,5 表示字符的总个数。
结果是:http:
6. 从左边第几个字符开始,一直到结束。
echo ${var:7}
其中的 7 表示左边第8个字符开始,一直到结束。
结果是 :www.aaa.com/123.htm
7. 从右边第几个字符开始,及字符的个数
echo ${var:0-7:3}
其中的 0-7 表示右边算起第七个字符开始,3 表示字符的个数。
结果是:123
8. 从右边第几个字符开始,一直到结束。
echo ${var:0-7}
表示从右边第七个字符开始,一直到结束。
结果是:123.htm
注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)
9. 字符串分割
大多数语言中都有类似string.split('sp') 的方法将字符串按照某个字符或子串切分成一个数组,shell 中可以如下
str="hello,world,i,like,you,babalala"
arr=(${str//,/ })
将str按照','切分成一个数组,并遍历之。当然,这里分隔符可以是一个子串。
三. 数组的操作
1. 定义数组
declare -a array # 显示声明了数组array
delcare -a array[10] # 数组大小没有上限,所以定义时指定的大小会被忽略
array[key]=value # array[0]=one,array[1]=two
array=(value1 value2...) # value的形式都是[subscript]=string,下标和等号可以省略,示例如下。
array=(value1 value2 value3) # array[0]=value1,array[1]=value2,array[2]=value3
array=([0]=value1 [2]=value3 [3]=value)
2. 访问数组
数组的任何元素都可以用 ${array[subscript]} 来引用,花括号是必须的,以避免和路径扩展冲突。 如果 subscript 是@或是*,它扩展为array的所有成员。这两种下标只有在双引号中才不同。在双引号中,${name[*]} 扩展为一个词,由所有数组成员的值组成,用特殊变量IFS的第一个字符分隔数组成员;${array[@]} 将array 的每个成员扩展为一个词。 如果数组没有成员,${name[@]} 扩展为空串。
3. 其他更多
请见https://www.thegeekstuff.com/2010/06/bash-array-tutorial/
四. 变量
1. 作用域
http://c.biancheng.net/view/773.html
2. 比较
https://blog.csdn.net/u010622613/article/details/80706119