shell read详解

本文会通过示例进行介绍文件读取的各种应用场景和代码案例,帮你快速了解shell的各种文件读取用法和学会最佳实践。

1. read详解

要与Linux交互,脚本获取键盘输入的结果是必不可少的,read可以读取键盘输入的字符。

read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量,用 IFS(内部字段分隔符)变量中的字符作为分隔符,默认情况下,read 命令会修改每一行的内容,即删除所有前导和尾随空格字符(如果存在于 IFS 中,则包括空格和制表符)

read [-rs] [-a ARRAY] [-d delim] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [var_name1 var_name2 ...]

如果没有指定任何var_name,则分割后的所有字段都存储在特定变量REPLY中。

]# read && echo "输入的是$REPLY"
123
输入的是123read
]# read input && echo "输入的是$input"
23rassf
输入的是23rassf

1.1. 选项说明

选项

说明

举例

-a array

把读取的数据赋值给数组 array,从下标 0 开始。

]# read -a arr && echo "输入的是${arr[@]}"

1 2 3

输入的是1 2 3

-d delimiter

指定读取结束的位置,而不是一个换行符(读取到的数据不包括 delimiter)

]# read -dc input <<< "abcde" && echo "$input"

ab

-e

在获取用户输入的时候,对功能键进行编码转换,不会直接显式功能键对应的字符。

]# read -e input <<< "1\t2\t3" && echo "$input"

1t2t3

-n num

一次只读取 num 个字符,而不是整行字符

]# read -n3 input <<< "abcde" && echo "$input"

abc

-p prompt

显示提示信息,提示内容为 prompt

]# read -p "请输入: " input && echo "你输入的是:"$input

请输入: 1

你输入的是:1

-r

原样读取(Raw mode),不把反斜杠字符解释为转义字符。

read -r input <<< "1\t2\t3" && echo "$input"

1\t2\t3

-s

静默模式(Silent mode),不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这是很有必要的。

]# read -s input && echo $input

sdfasdfd

-t seconds

设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么 read 将会返回一个非 0 的退出状态,表示读取失败。

#2秒内输入,打印返回值
[root@docker01 ~]# read -t 2 input && echo $input && echo $?

0

#2秒内不输入,打印返回值

[root@docker01 ~]# read -t 2 input && echo $input || echo $?

142

-u fd

使用文件描述符 fd 作为输入源,而不是标准输入,类似于重定向。

]# while read -u3 i && read -u4 j; do echo "i=$i,j=$j"; done 3< "1.txt" 4<"2.txt"

i=a,j=1

i=b,j=2

i=c,j=3

现在的写法,相当于只对 while 语句进行重定向,while结束后,3,4 就没有了。

如果想在 while后继续访问,那么可以考虑用 exec 3<afile 的方式。

IFS

默认的IFS是空格和制表符,通过指定IFS可以进行按指定的符号进行分割字符串

]# IFS=',' read a b c <<< "1,2,3" && echo "$a,$b,$c"

1,2,3

]# while IFS=: read -r user pass uid gid gecos home shell; do printf '%s: %s\n' "$user" "$shell"; done < /etc/passwd

root: /bin/bash

bin: /sbin/nologin

读取变量不匹配

1.若定义变量大于实际的字符数,多余的变量为空,

2.若定义变量小于实际的字符数,则多余的字符全给最后一个变量

#定义变量大于实际的字符数,多余的变量为空

]# read -r a b c d e f <<< "1 2 3" && echo "$a,$b,$c,$d,$e,$f"

1,2,3,,,

#定义变量小于实际的字符数,则多余的字符全给最后一个变量

]# read -r a b c <<< "1 2 3 4 5" && echo $a, $b, $c

1, 2, 3 4 5

_

占位符变量,来忽略字段。它也可以在单个 read 命令中使用多次,需要注意的是,只有在 Bash 中使用 _ 才能保证能够正常工作。许多其他 shell 使用 _ 来表示其他用途,这可能会导致该脚本失效

read name _ _ age <<< "tom 170 43222 18" && echo $name,$age

# 跳过前两个字段读取后续的. 下划线可以忽略多个

2. read配合while读取文件

2.1. < "file" 读取文件

告诉while循环从变量file 中保存的文件名中读取。

while read -r line; do
  printf '%s\n' "$line"
done < "1.txt"

2.2. << Heredocs 导入文件

Heredocs 是一种用于将多行文本传递给命令或脚本的方法。使用 Heredocs 可以将文本嵌入到 Shell 脚本中,而无需将文本存储在外部文件中。Heredocs 使用 << 运算符,后跟一个自定义的标识符来标识文本块的开头。然后在接下来的行中输入文本,直到行中包含该标识符,并且不希望将其包含在文本中为止。例如:

]# cat >> 1.test <<EOF
> abcdefg
> aa
> EOF
[root@docker01 ~]# cat 1.test 
abcdefg
aa
#在上面的示例中,<<EOF 表示 Heredocs 的开始,
#EOF 是自定义的标识符。然后在接下来的行中,输入要嵌入的文本,直到再次输入 END 为止。
#在此示例中,cat 命令将输出 Heredocs 中的文本。
----------------------------------------------------------------------------------------
]# cat  1.txt 
a
b
c
]# while read line;do echo $line;done << EOF
> `cat 1.txt`
> EOF
a
b
c
#<<是把文件分多行传入while循环

2.3. <<< Herestrings:

Herestrings 是一种将文本传递给命令或脚本的方法,类似于 Heredocs。但是,它们使用单行文本,而不是多行文本,并且不需要自定义标识符。Herestrings 使用 <<< 运算符,后跟一个字符串来传递文本。

grep foo <<< "This is a line of text containing the word foo."
#在上面的示例中,<<< 运算符将字符串 "This is a line of text containing the word foo." 
#传递给 grep 命令。grep 命令将输出包含字符串 foo 的行。
-------------------------------------------------------------------------
]# cat  1.txt 
a
b
c
]# while read line;do echo $line;done <<< `cat 1.txt`
a b c
#<<是把文件按一行传入while循环

2.4. 管道读取文件

]# cat 1.txt|while read -r line;do echo $line;done
a
b
c

2.5. 自定义文件描述符作为输入源

#-u3,指定把名为3的描述符作为输入源
#3<'1.txt'是定义一个文件描述符名称为3,并把文件输入到这个描述符里面
]# while read -u3 i && read -u4 j; do  echo "i=$i,j=$j"; done 3< "1.txt" 4<"2.txt"
i=a,j=1
i=b,j=2
i=c,j=3
---------------------------------------------------------------------------------
#自定义输入源,可以同时进行多个文件读取,也可以在读取文件的时候,读取标准输入的内容
#写法一:read -u定义新的输入源
while read -u4 line
do 
  read t && echo $t >> tmp.txt
  echo "文件读取行:"$line
done 4< 1.txt
cat tmp.txt

adfa
文件读取行:a
adfads
文件读取行:b
afda
文件读取行:c
adfa
adfads
afda
#这里又能输出文件内容,同时也能读取标准输入的内容

# 写法二:read -u并非所有shell都支持,所以这种也可以
while read line <&4
do 
  read t && echo $t >> tmp.txt
  echo "文件读取行:"$line
done 4< 1.txt 
cat tmp.txt

#写法三:
exec 4< "1.txt"
while read line <&4
do 
  read t && echo $t >> tmp.txt
  echo "文件读取行:"$line
done
exec 4<&-
cat tmp.txt

2.6. 非正常文件处理方式

如果文件的最后一行后面还有一些字符(或者换句话说,如果最后一行没有以换行符终止),那么 read 命令将读取该行内容,但会返回 false,同时将未完成的部分行留在 read 变量中。您可以在循环后处理这些行:

while IFS= read -r line; do
  printf '%s\n' "$line"
done < "$file"
[[ -n $line ]] && printf %s "$line"
#-n是判断$line非空

或者

# 只打印了一行
]# printf 'line 1\ntruncated line 2' | while read -r line; do echo $line; done
line 1

# 只打印了一行
]# printf 'line 1\ntruncated line 2' | while read -r line; do echo "$line"; done; [[ $line ]] && echo -n "$line"
line 1

# 这个处理方式符合预期:
]# printf 'line 1\ntruncated line 2' | { while read -r line; do echo "$line"; done; [[ $line ]] && echo "$line"; }
line 1
truncated line 2

或者,您可以在 while 测试中添加逻辑 OR 操作符:

while IFS= read -r line || [[ -n $line ]]; do
  printf '%s\n' "$line"
done < "$file"

printf 'line 1\ntruncated line 2' | while read -r line || [[ -n $line ]]; do echo "$line"; done

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值