文档章节

【原创】shell 操作之 read、cat 和 here document

摩云飞
 摩云飞
发布于 2014/11/07 10:27
字数 4750
阅读 3820
收藏 146

本文主要学习总结一下三方面问题:
  1. 通过 read 进行行读
  2. here document
  3. here document 的应用

【read】

在 linux 下执行 man read 能看到如下内容
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] 
    One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option, 
and the first word is assigned to the first name, the second word to the second name, and so on, with leftover words and 
their intervening separators assigned to the last name. If there are fewer words read from the input stream than names, 
the remaining names are assigned empty values. The characters in IFS are used to split the line into words. The backslash 
character (\) may be used to remove any special meaning for the next character read and for line continuation. Options, 
if supplied, have the following meanings: 
    从标准输入上读取一行数据,或者从通过 -u 选项指定的文件描述符 fd 上读取,并且按照顺序,将读取的第一个 word 赋值给第一个 name ,第二个 
word 赋值给 name ,以此类推,对于剩余的 words 和 word 之间的分隔符都被赋值到最后一个 name 上。如果从输入流上读取的 word 的数量少于给出
的 name 数量,则多出来的 names 将被自动赋值为空值。IFS 中所包含的字符用于将整行字符拆分成单独的 word (换句话说也就是将 IFS 中包含的字符
从行数据中去除,IFS 中默认包含的字符为空格、制表符和回车)。反斜线字符(\)可以用于移除紧随其后读到的字符的任何特殊含义,还可用于行接续。
若提供了选项,则具有如下意义: 
    -a aname 
        The words are assigned to sequential indices of the array variable aname, starting at 0. aname is unset before 
        any new values are assigned. Other name  arguments are ignored. 
  
    -d delim 
        The first character of delim is used to terminate the input line, rather than newline. 
        delim 的首字符被用于作为输入行数据的终止符,而不是换行符。 
    -e 
        If the standard input is coming from a terminal, readline (see READLINE above) is used to obtain the line. 
        Readline uses the current (or default, if line editing was not previously active) editing settings. 
    -i text 
        If readline is being used to read the line, text is placed into the editing buffer before editing begins. 
    -n nchars 
        read returns after reading nchars characters rather than waiting for a complete line of input, but honor a delimiter 
        if fewer than nchars characters are read  before the delimiter. 
    -N nchars 
        read returns after reading exactly nchars characters rather than waiting for a complete line of input, unless EOF 
        is encountered or read times out. 
        Delimiter characters encountered in the input are not treated specially and do not cause read to return until 
        nchars characters are read. 
    -p prompt 
        Display prompt on standard error, without a trailing newline, before attempting to read any input. The prompt is 
        displayed only if input is coming from a  terminal. 
        在开始读取任何输入前,向标准出错上显示提示信息,并且不带尾部换行符。该提示信息仅在输入数据来自终端的时候才被显示。 
    -r  Backslash does not act as an escape character. The backslash is considered to be part of the line.  
        In particular, a backslash-newline pair may not be used as a line continuation. 
        反斜线不作为转义字符起作用。反斜线被当做行数据的一部分。 
        特别值得注意的是,反斜线-换行 组合将不能作为行接续来使用。 
    -s  Silent mode. If input is coming from a terminal, characters are not echoed. 
        安静模式。如果输入来自终端,字符将不会被 echo 。 
    -t timeout 
        Cause read to time out and return failure if a complete line of input is not read within timeout seconds. timeout 
        may be a decimal number with a fractional  portion following the decimal point. This option is only effective if read 
        is reading input from a terminal, pipe, or other special file; it has no effect when reading from regular files. If 
        timeout is 0, read returns success if input is available on the specified file descriptor, failure otherwise. The exit 
        status is greater than 128 if the timeout is exceeded. 
    -u fd
        Read input from file descriptor fd. 
        从文件 fd 读取输入数据。 

    If no names are supplied, the line read is assigned to the variable REPLY. The return code is zero, unless end-of-file 
is encountered, read times out (in which case the return code is greater than 128), or an invalid file descriptor is supplied 
as the argument to -u. 
    如果没有 name 变量被指定,所读取的行数据将被赋值给变量 REPLY 。除非遇到了文件结束符(EOF),或者发生读取超时(此时返回值将大于 128),或者
通过 -u 指定了无效的文件描述符,其他情况返回值均为 0 。

【read 测试】

测试文件如下
[root@Betty Shell]# vi file

 -module( unique_name_test      )    . 
-compile(export_all). 

%% @spec (Nibble::integer()) -> char() 
%% @doc Returns the character code corresponding to Nibble. 
%% 
%% Nibble must be >=0 and =<16. 
hex_digit(0) -> $0; 
hex_digit(1) -> $1; 
hex_digit(2) -> $2; 
hex_digit(3) -> $3; 
hex_digit(4) -> $4; 
hex_digit(5) -> $5; 
hex_digit(6) -> $6; 
hex_digit(7) -> $7; 
hex_digit(8) -> $8; 
hex_digit(9) -> $9; 
hex_digit(10) -> $A; 
hex_digit(11) -> $B; 
hex_digit(12) -> $C; 
hex_digit(13) -> $D; 
hex_digit(14) -> $E; 
hex_digit(15) -> $F.

测试一:读取文件的首行并赋值给变量

[root@Betty Shell]# read -r line < file      
[root@Betty Shell]# echo $line          
-module( unique_name_test ) .
      这一行命令用到了 Bash 的内置命令 read,和输入重定向操作符 < 。read 命令从标准输入中读取一行,并将内容保存到变量 line 中。在这里,-r 选项保证读入的内容是原始的内容,意味着反斜杠转义的行为不会发生。输入重定向操作符 < file 打开并读取文件 file ,然后将它作为 read 命令的标准输入。

      记住,read 命令会删除包含在 IFS 变量中出现的所有字符(这个说法似乎不够准确),IFS 的全称是 Internal Field Separator,Bash 根据 IFS 中定义的字符来分隔单词。在这里,read 命令读入的行被分隔成多个单词。默认情况下,IFS 包含空格,制表符和回车,这意味着开头和结尾的空格和制表符都会被删除。如果你想保留这些符号,可以通过设置 IFS 为空来完成:
[root@Betty Shell]# IFS= read -r line < file 
[root@Betty Shell]# echo $line               
-module( unique_name_test ) .
IFS 的变化仅会影响当前的命令,这行命令可以保证读入原始的首行内容到变量 line 中,同时行首与行尾的空白字符被保留。

测试二:依次读入文件每一行

[root@Betty Shell]# while read -r line; do
> echo "test $line";
> done < file
test -module( unique_name_test  )    .
test
test -compile(export_all).
test
test
test %% @spec (Nibble::integer()) -> char()
test %% @doc Returns the character code corresponding to Nibble.
test %%
test %% Nibble must be >=0 and =&lt;16.
test hex_digit(0) -> $0;
test hex_digit(1) -> $1;
test hex_digit(2) -> $2;
test hex_digit(3) -> $3;
test hex_digit(4) -> $4;
test hex_digit(5) -> $5;
test hex_digit(6) -> $6;
test hex_digit(7) -> $7;
test hex_digit(8) -> $8;
test hex_digit(9) -> $9;
test hex_digit(10) -> $A;
test hex_digit(11) -> $B;
test hex_digit(12) -> $C;
test hex_digit(13) -> $D;
test hex_digit(14) -> $E;
test hex_digit(15) -> $F.
test
test
[root@Betty Shell]#
      这是一种正确的读取文件内容的做法,read 命令放在 while 循环中。当 read 命令遇到文件结尾时(EOF),它会返回一个正值,导致循环判断失败终止。

=== 我是火影终结的分隔线 ===

关于 read 命令遇到文件结尾返回一个正值的结论,之前我一直持怀疑态度。因为经常会遇到这样的用法:
while read -r line; do echo $line; done < file
而按照常规编程思维,while 循环的判定条件应该是不为 0 则循环,似乎这里就出现了矛盾。
于是进行如下实验进行验证
[root@Betty workspace]# touch abc.txt
[root@Betty workspace]# cat abc.txt 
[root@Betty workspace]# read -r line < abc.txt  
[root@Betty workspace]# echo $?
1
[root@Betty workspace]# echo "1" >> abc.txt
[root@Betty workspace]# cat abc.txt            
1
[root@Betty workspace]# read -r line < abc.txt 
[root@Betty workspace]# echo $?
0
结果证明,read 读到文件结束时确实返回 1 ,而读到内容时返回 0 。
最后再确认一下 while 的判定规则
while list; do list; done
    The while command continuously executes the do list as long as the last command in list returns an exit status 
of zero. The exit status of the while commands is the exit status of the last do list command executed, or zero if 
none was executed.
哈哈,套用工藤新一的话“真相只有一个”~~

=== 我是火影终结的分隔线 ===


记住,read 命令会删除首尾多余的空白字符,所以如果你想保留,请设置 IFS 为空值:

[root@Betty Shell]# while IFS= read -r line; do  
> echo "test $line"; 
> done < file 
test  -module( unique_name_test )    .    
test  
test -compile(export_all). 
test  
test  
test %% @spec (Nibble::integer()) -> char() 
test %% @doc Returns the character code corresponding to Nibble. 
test %% 
test %% Nibble must be >=0 and =&lt;16. 
test hex_digit(0) -> $0; 
test hex_digit(1) -> $1; 
test hex_digit(2) -> $2; 
test hex_digit(3) -> $3; 
test hex_digit(4) -> $4; 
test hex_digit(5) -> $5; 
test hex_digit(6) -> $6; 
test hex_digit(7) -> $7; 
test hex_digit(8) -> $8; 
test hex_digit(9) -> $9; 
test hex_digit(10) -> $A; 
test hex_digit(11) -> $B; 
test hex_digit(12) -> $C; 
test hex_digit(13) -> $D; 
test hex_digit(14) -> $E; 
test hex_digit(15) -> $F. 
test  
test  
[root@Betty Shell]#
      从上面可以看出 < file 永远是放在最后的,如果你不想将 < file 放在最后,可以通过管道将文件的内容输入到 while 循环中:
[root@Betty Shell]# cat file | while IFS= read -r line; do  
> echo "test $line"; 
> done 
test  -module( unique_name_test )    .    
test  
test -compile(export_all). 
test  
test  
test %% @spec (Nibble::integer()) -> char() 
test %% @doc Returns the character code corresponding to Nibble. 
test %% 
test %% Nibble must be >=0 and =&lt;16. 
test hex_digit(0) -> $0; 
test hex_digit(1) -> $1; 
test hex_digit(2) -> $2; 
test hex_digit(3) -> $3; 
test hex_digit(4) -> $4; 
test hex_digit(5) -> $5; 
test hex_digit(6) -> $6; 
test hex_digit(7) -> $7; 
test hex_digit(8) -> $8; 
test hex_digit(9) -> $9; 
test hex_digit(10) -> $A; 
test hex_digit(11) -> $B; 
test hex_digit(12) -> $C; 
test hex_digit(13) -> $D; 
test hex_digit(14) -> $E; 
test hex_digit(15) -> $F. 
test  
test  
[root@Betty Shell]#

测试三:读取文件首行前三个字段并赋值给变量

[root@Betty Shell]# head -1 file | while read -r field1 field2 field3 throwaway; do echo "filed1 = $field1";echo "field2 = $field2";echo "field3 = $field3"; done    
filed1 = -module( 
field2 = unique_name_test 
field3 = )
      如果在 read 命令中指定多个变量名,它会将读入的内容分隔成多个字段,然后依次赋值给对应的变量,第一个字段赋值给第一个变量,第二个字段赋值给第二个变量,等等,最后将剩余的所有字段赋值给最后一个变量。这也是为什么,在上面的例子中,我们加了一个 throwaway 变量,否则的话,当文件的一行大于三个字段时,第三个变量的内容会包含所有剩余的字段。
      有时候,为了书写方便,可以简单地用 _ 来替换 throwaway 变量:
[root@Betty Shell]# head -1 file | while read -r field1 field2 field3 _; do echo "filed1 = $field1";echo "field2 = $field2";echo "field3 = $field3"; done 
filed1 = -module( 
field2 = unique_name_test 
field3 = )
又或者,如果你的文件确实只有三个字段,可以忽略 _ 。

【cat 与 <<】

  • cat 命令是 linux 下的一个文本输出命令,通常是用于观看某个文件的内容的; 命令 cat >file 可以用于将键盘上的输入写到文件中。
  • EOF 为 "end of file" 的缩写,从语义上代表文本的结束符。
  • 通过 cat <<EOF 将两者结合使用(EOF 和 << 中间是否有空格没有关系),即可避免使用多行 echo 命令的方式,并实现多行输出的结果。原则上讲,此处的 EOF 可以使用任何其他字符替代。

测试 - 1

cat > test.cfg <<EOF 
log_facility=daemon 
pid_file=/var/run/nrpe.pid 
EOF

测试 - 2

cat > test.cfg <<ABC 
log_facility=daemon 
pid_file=/var/run/nrpe.pid 
ABC

测试 - 3

cat <<ABC > test.cfg 
log_facility=daemon 
pid_file=/var/run/nrpe.pid 
ABC

【Here document】

  • 有写书籍将 here document 翻译为内嵌文档。
  • here document 的别名有 here-document 、heredoc 、hereis 、 here-string 或 here-script 。
  • here document 原本指 file literal 或者 input stream literal ;后来也指 multiline string literals 。
  • here document 会保留 text 中的 line break 和其他 whitespace (including indentation) 的含义。
  • here document 起始于 Unix shell ,后在各种其他 shell 中被使用。
  • here document 风格的字符串在很多高级语言中存在,尤其是 Perl 语言和其他受 Perl 影响的语言,如 PHP 和 Ruby 。
  • 对于 here document 而言,无论指代的是文件还是字符串,一些语言都将其看做格式化字符串,并允许在其内部进行变量替换和命令替代。
  • here document 的最通用语法起源于 Unix shell ,使用 "<< delimiter" 的形式(delimiter 通常为 EOF 或 END)标识多行字串的开始,之后新起一行包含相应的文本,最后以相同的 delimiter 独占一行标识多行字串的结束。这种语法形式是因为 here documents 主要用于 stream literal ,且 document 的内容被重定向到前面 command 的标准输入,即 here document 的语法模拟了输入重定向的语法,也就是 < 所表示的“从后续 command 的输出获取输入”。
  • 其它语言通常使用了非常相似的语法,但是语法的细节和实际的功能可能非常的不同。

Unix shell 中的应用

In the following example, text is passed to the tr command using a here document. This could be in a shell file, or entered interactively at a prompt.
[root@Betty Shell]# tr a-z A-Z << END_TEXT 
> one two three 
> uno dos tres 
> END_TEXT
This yields the output:
ONE TWO THREE 
UNO DOS TRES
此处使用  <<END_TEXT 或 << END_TEXT 都正确。

在 << 后添加 - 符号的作用是可以忽略掉前置的 tab 。这将允许在 shell 命令行上直接对包含缩进的 here document 进行操作,而不用变更脚本的内容。
注意:要想在 shell 命令行上输入 TAB ,需要连续输入 CTRL-V 、TAB 才行。
[root@Betty Shell]# tr a-z A-Z <<- END_TEXT 
>(Ctrl-V + TAB)one two three 
>(Ctrl-V + TAB)uno dos tres 
>(Ctrl-V + TAB)END_TEXT
This yields the same output, notably not indented:
ONE TWO THREE 
UNO DOS TRES

补充测试:
[root@Betty Shell]# tr a-z A-Z << END_TEXT  
>(Ctrl-V + TAB)one two three 
>(Ctrl-V + TAB)uno dos tres 
>(Ctrl-V + TAB)END_TEXT 
> END_TEXT
将得到
(Ctrl-V + TAB)ONE TWO THREE 
(Ctrl-V + TAB)UNO DOS TRES 
(Ctrl-V + TAB)END_TEXT

在默认情况下,变量将被内插替换,包含在 `` 中的命令将被求值。
backtick 即传说中的反引号。
[root@Betty Shell]# cat << EOF 
> Working dir $PWD 
> EOF
yields:
Working dir /root/workspace/CODE_TEST/Shell
上述行为可以通过引号引用标签的任何部分进行取消。例如,将 EOF 使用单引号或者双引号进行包含:
[root@Betty Shell]# cat << "EOF" 
> Working dir $PWD 
> EOF
yields:
Working dir $PWD

补充测试:
[root@Betty Shell]# cat << "E"OF 
Working dir $PWD 
EOF
将得到
Working dir $PWD

(后面还有对 here string 的介绍,此处略过)

man 手册上的说明

Here Documents
      This type of redirection instructs the shell to read input from the current source until a line containing only delimiter (with no trailing blanks) is seen. All of the lines read up to that point are then used as the standard input for a command.
      这种类型的重定向会使得 shell 从当前源读取输入,直到遇到仅包含 delimiter 的行(尾部没有任何空白符)。此时读取到的全部行将被作为 command 的标准输入。

       The format of here-documents is:

              <<[-]word
                      here-document
              delimiter

       No parameter expansion, command substitution, arithmetic expansion, or pathname expansion is performed on word. If any characters in word are quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion. In the latter case, the character sequence \<newline> is ignored, and \ must be used to quote the characters \, $, and `.
      针对 word 不会执行任何参数扩展、命令替代、算数扩展,或路径扩展。如果 word 中有任何字符是被引号括起来的,那么 delimiter 将是 word 移除引用部分后的内容,此时位于 here-document 中的行将不会被扩展,如果 word 没有被引号括起来,here-document 中的所有行都要受到参数扩展、命令替换和算数扩展的影响。在后者的情况下,字符序列 \<newline> 会被忽略,并且只要存在 \,$ 和 ` 字符都要使用 \ 进行转义(如果你确实打算输出未被转义的字符)。

       If the redirection operator is <<-, then all leading tab characters are stripped from input lines and the line containing delimiter.  This allows here-documents  within shell scripts to be indented in a natural fashion.
      如果重定向操作符为 <<- ,那么所有前置 tab 字符都将被从输入的行数据和仅包含 delimiter 的行中移除。这将使得 here-document 用于 shell 脚本时能够以自然方式进行缩进。

Here Strings
       A variant of here documents, the format is:

              <<<word

       The word is expanded and supplied to the command on its standard input.


=== 我是 7 代的分隔线 ===

stackoverflow 上的讨论

在  stackoverflow 上有如下针对 bash 中使用   cat << EOF 的讨论。

bash 语法 cat <<EOF 在你遇到 Bash 上使用多行字符串的时候是非常有用的,例如,当传递多行字串到一个变量、文件,或者管道中的情况。
例子一: 将多行字符串传递给一个变量 (原文中的测试此处被我加强了)
[root@Betty Shell]# sql=$(cat <<EOF 
> SELECT foo, bar FROM db 
> WHERE foo='baz' 
> EOF 
> ) 
[root@Betty Shell]#  
[root@Betty Shell]# echo $sql     
SELECT foo, bar FROM db WHERE foo='baz' 
[root@Betty Shell]#  
[root@Betty Shell]# echo -e $sql                     -e     enable interpretation of backslash escapes 
SELECT foo, bar FROM db WHERE foo='baz' 
[root@Betty Shell]#  
[root@Betty Shell]# echo -E $sql                     -E     disable interpretation of backslash escapes (default) 
SELECT foo, bar FROM db WHERE foo='baz' 
[root@Betty Shell]#  
[root@Betty Shell]# echo "$sql" 
SELECT foo, bar FROM db 
WHERE foo='baz' 
[root@Betty Shell]#  
[root@Betty Shell]# echo -e "$sql"                   -e     enable interpretation of backslash escapes 
SELECT foo, bar FROM db 
WHERE foo='baz' 
[root@Betty Shell]#  
[root@Betty Shell]# echo -E "$sql"                   -E     disable interpretation of backslash escapes (default) 
SELECT foo, bar FROM db 
WHERE foo='baz' 
[root@Betty Shell]#
      执行后,$sql 变量中将会包含带换行符的字串,你可以通过 echo -e "$sql" 命令进行查看。
(上面的结论和我自己的实验结果有出入,按照原文的说法,shell 命令输入时是带有 \n 字符的,并且只有在 -e 选项下能被解析,然而实验结果表明,只要将 $sql 用双引号括起来,结果一定是带有换行符的;而不用双引号括起来的 $sql 则被显示为单行。这里引出一个问题,"$sql" 和 $sql 在 shell 中的区别是什么?)

例子二:将多行字符串传递给一个文件
[root@Betty Shell]# cat <<EOF > print.sh 
> #!/bin/bash 
> echo \$PWD 
> echo $PWD 
> EOF
The print.sh file now contains:
[root@Betty Shell]# cat print.sh  
#!/bin/bash 
echo $PWD                              -- 未被命令替换 
echo /root/workspace/CODE_TEST/Shell   -- 被命令替换
例子三:将多行字符串传递给一个 command/pipe
[root@Betty Shell]# cat <<EOF | grep 'b' | tee b.txt | grep 'r' 
> foo 
> bar 
> baz 
> EOF 
bar
上述命令只将 bar 打印到标准输出,但会创建 b.txt 文件,其中包含了 bar 和 baz 两行字符串。

===

      在上面的例子中,"EOF" 被用作 "Here Tag" 。简单的讲,"<< Here" 的作用就在于告诉 shell 下面将开始一段多行字符串输入,并且该多行字符串以 "Here" 作为终止。你也可以将 "Here" 替换成任何你想要的内容,但通常会使用 EOF 或者 STOP 。

一些关于 Here 标签的规则:
  • 标签可以是任何字符串,大小写字母均可,但通常人们习惯使用大写字母。
  • 若(尾部)标签所在行还存在其他字符,则该标签将不作为标签起作用。在这种情况下,该标签将仅作为字符串的一部分。标签必须自身独占一行才会被判定为正确的标签。
  • 标签所在行中的标签不应该具有前置或后置的空白符,只有这样才被判定为正确的标签。否则会被认为是字符串的一部分。
[root@Betty Shell]# cat >> test <<HERE 
> Hello world HERE               <--- Not the end of string 
>   HERE                         <-- Leading space, so not end of string 
> HERE                           <-- Now we have the end of the string 
[root@Betty Shell]# cat test  
Hello world HERE 
  HERE

参考

1. Linux man 手册
2. bash read 背后的故事二:read -r
3. 关于 cat > file 和 cat > file <<EOF
4. Here document 
5. how does ` cat << EOF` work in bash? 


© 著作权归作者所有

共有 人打赏支持
摩云飞
粉丝 368
博文 534
码字总数 952694
作品 0
徐汇
程序员
加载中

评论(17)

摩云飞
摩云飞
(在 @int03h 的回复里看不到格式,在这里重发一下)其实我上面的测试主要是想说明下面这个的区别:
[root@Betty Shell]# echo ' \t\n'
_\t\n
[root@Betty Shell]# echo " \t\n"
_\t\n
[root@Betty Shell]# echo $' \t\n'
_

[root@Betty Shell]# echo $" \t\n"
_\t\n
[root@Betty Shell]#
没办法,空格显示不出来,只能用 _ 代替了~~将就看下吧
摩云飞
摩云飞

引用来自“摩云飞”的评论

针对你的实验,我也进行了如下测试: 查看 set 命令查看 shell 变量可以发现
[root@Betty ~]# set
...
IFS=$' \t\n'
...

因为 IFS 的内容为 whitespace ,所以直接 echo 是看不到东西的。
[root@Betty ~]# echo $IFS

[root@Betty ~]#

通过如下方式查看不同情况下 IFS 的值(也可以使用 od -x xxx 效果相同):
[root@Betty ~]# echo $IFS > ifs_1.txt
[root@Betty ~]# IFS= echo $IFS > ifs_2.txt
[root@Betty ~]# echo "$IFS" > ifs_3.txt
[root@Betty ~]# IFS= echo "$IFS" > ifs_4.txt
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_1.txt
0000000 000a
0000001
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_2.txt
0000000 000a
0000001
[root@Betty ~]# hexdump ifs_3.txt
0000000 0920 0a0a
0000004
[root@Betty ~]# hexdump ifs_4.txt
0000000 0920 0a0a
0000004
[root@Betty ~]#
这个实验说明:
1.在 echo 命令前使用 IFS= 并没有起到作用;
2.对于定义为 IFS=$' \t\n' 的 IFS ,"$IFS" 和 $IFS 是有区别的。
所以,其实本文中对 IFS 的使用,还有一些疑点可以继续探讨的~~~

引用来自“int03h”的评论

这个,其实是bash中""用法的原因,在bash中,""能保留除$和``和$()的其它字符,即是说,空格和tap和换行均不会被忽略。而$和``和$()会被解释。另外还有一个'',这个是全保留,就是说,所有字符都不会被解释。例子: # test=123 # echo "$test\t" 123\t echo '$test\t' $test\t 更具体的可以百度 "bash 单引号 双引号"
其实我上面的测试主要是想说明下面这个的区别: [root@Betty Shell]# echo ' \t\n' \t\n [root@Betty Shell]# echo " \t\n" \t\n [root@Betty Shell]# echo $' \t\n' [root@Betty Shell]# echo $" \t\n" \t\n [root@Betty Shell]#
摩云飞
摩云飞

引用来自“摩云飞”的评论

针对你的实验,我也进行了如下测试: 查看 set 命令查看 shell 变量可以发现
[root@Betty ~]# set
...
IFS=$' \t\n'
...

因为 IFS 的内容为 whitespace ,所以直接 echo 是看不到东西的。
[root@Betty ~]# echo $IFS

[root@Betty ~]#

通过如下方式查看不同情况下 IFS 的值(也可以使用 od -x xxx 效果相同):
[root@Betty ~]# echo $IFS > ifs_1.txt
[root@Betty ~]# IFS= echo $IFS > ifs_2.txt
[root@Betty ~]# echo "$IFS" > ifs_3.txt
[root@Betty ~]# IFS= echo "$IFS" > ifs_4.txt
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_1.txt
0000000 000a
0000001
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_2.txt
0000000 000a
0000001
[root@Betty ~]# hexdump ifs_3.txt
0000000 0920 0a0a
0000004
[root@Betty ~]# hexdump ifs_4.txt
0000000 0920 0a0a
0000004
[root@Betty ~]#
这个实验说明:
1.在 echo 命令前使用 IFS= 并没有起到作用;
2.对于定义为 IFS=$' \t\n' 的 IFS ,"$IFS" 和 $IFS 是有区别的。
所以,其实本文中对 IFS 的使用,还有一些疑点可以继续探讨的~~~

引用来自“int03h”的评论

这个,其实是bash中""用法的原因,在bash中,""能保留除$和``和$()的其它字符,即是说,空格和tap和换行均不会被忽略。而$和``和$()会被解释。另外还有一个'',这个是全保留,就是说,所有字符都不会被解释。例子: # test=123 # echo "$test\t" 123\t echo '$test\t' $test\t 更具体的可以百度 "bash 单引号 双引号"
恩,我已经把相关用法添加到《【转载】书写优雅的shell脚本》中了,地址:http://my.oschina.net/moooofly/blog/340187 。谢谢你的指出~~
int03h
int03h

引用来自“摩云飞”的评论

针对你的实验,我也进行了如下测试: 查看 set 命令查看 shell 变量可以发现
[root@Betty ~]# set
...
IFS=$' \t\n'
...

因为 IFS 的内容为 whitespace ,所以直接 echo 是看不到东西的。
[root@Betty ~]# echo $IFS

[root@Betty ~]#

通过如下方式查看不同情况下 IFS 的值(也可以使用 od -x xxx 效果相同):
[root@Betty ~]# echo $IFS > ifs_1.txt
[root@Betty ~]# IFS= echo $IFS > ifs_2.txt
[root@Betty ~]# echo "$IFS" > ifs_3.txt
[root@Betty ~]# IFS= echo "$IFS" > ifs_4.txt
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_1.txt
0000000 000a
0000001
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_2.txt
0000000 000a
0000001
[root@Betty ~]# hexdump ifs_3.txt
0000000 0920 0a0a
0000004
[root@Betty ~]# hexdump ifs_4.txt
0000000 0920 0a0a
0000004
[root@Betty ~]#
这个实验说明:
1.在 echo 命令前使用 IFS= 并没有起到作用;
2.对于定义为 IFS=$' \t\n' 的 IFS ,"$IFS" 和 $IFS 是有区别的。
所以,其实本文中对 IFS 的使用,还有一些疑点可以继续探讨的~~~
这个,其实是bash中""用法的原因,在bash中,""能保留除$和``和$()的其它字符,即是说,空格和tap和换行均不会被忽略。而$和``和$()会被解释。另外还有一个'',这个是全保留,就是说,所有字符都不会被解释。例子: # test=123 # echo "$test\t" 123\t echo '$test\t' $test\t 更具体的可以百度 "bash 单引号 双引号"
摩云飞
摩云飞
针对你的实验,我也进行了如下测试: 查看 set 命令查看 shell 变量可以发现
[root@Betty ~]# set
...
IFS=$' \t\n'
...

因为 IFS 的内容为 whitespace ,所以直接 echo 是看不到东西的。
[root@Betty ~]# echo $IFS

[root@Betty ~]#

通过如下方式查看不同情况下 IFS 的值(也可以使用 od -x xxx 效果相同):
[root@Betty ~]# echo $IFS > ifs_1.txt
[root@Betty ~]# IFS= echo $IFS > ifs_2.txt
[root@Betty ~]# echo "$IFS" > ifs_3.txt
[root@Betty ~]# IFS= echo "$IFS" > ifs_4.txt
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_1.txt
0000000 000a
0000001
[root@Betty ~]#
[root@Betty ~]# hexdump ifs_2.txt
0000000 000a
0000001
[root@Betty ~]# hexdump ifs_3.txt
0000000 0920 0a0a
0000004
[root@Betty ~]# hexdump ifs_4.txt
0000000 0920 0a0a
0000004
[root@Betty ~]#
这个实验说明:
1.在 echo 命令前使用 IFS= 并没有起到作用;
2.对于定义为 IFS=$' \t\n' 的 IFS ,"$IFS" 和 $IFS 是有区别的。
所以,其实本文中对 IFS 的使用,还有一些疑点可以继续探讨的~~~
摩云飞
摩云飞

引用来自“int03h”的评论

1然后,我又测试了一下。。。
# PATH= ls
-bash: ls: 没有那个文件或目录
#PATH= echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
一瞬间,我明白了。这并没有清变量,只是令环境变量在那一行无效化。。。
针对你的实验,我也进行了如下测试: 查看 set 命令查看 shell 变量可以发现 [root@Betty ~]# set ... IFS=$' \t\n' ... 因为 IFS 的内容为 whitespace ,所以直接 echo 是看不到东西的。 [root@Betty ~]# echo $IFS [root@Betty ~]# 通过如下方式查看不同情况下 IFS 的值(也可以使用 od -x xxx 效果相同): [root@Betty ~]# echo $IFS > ifs_1.txt [root@Betty ~]# IFS= echo $IFS > ifs_2.txt [root@Betty ~]# echo "$IFS" > ifs_3.txt [root@Betty ~]# IFS= echo "$IFS" > ifs_4.txt [root@Betty ~]# [root@Betty ~]# hexdump ifs_1.txt 0000000 000a 0000001 [root@Betty ~]# [root@Betty ~]# hexdump ifs_2.txt 0000000 000a 0000001 [root@Betty ~]# hexdump ifs_3.txt 0000000 0920 0a0a 0000004 [root@Betty ~]# hexdump ifs_4.txt 0000000 0920 0a0a 0000004 [root@Betty ~]# 这个实验说明: 1.在 echo 命令前使用 IFS= 并没有起到作用; 2.对于定义为 IFS=$' \t\n' 的 IFS ,"$IFS" 和 $IFS 是有区别的 所以,其实本文中对 IFS 的使用,还有一些疑点可以继续探讨的~~~
摩云飞
摩云飞

引用来自“tinyhare”的评论

都被赋值到"最有一个" name 上。0
已修正
tinyhare
tinyhare
都被赋值到"最有一个" name 上。0
摩云飞
摩云飞

引用来自“int03h”的评论

1然后,我又测试了一下。。。
# PATH= ls
-bash: ls: 没有那个文件或目录
#PATH= echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
一瞬间,我明白了。这并没有清变量,只是令环境变量在那一行无效化。。。
恩恩,你的实验验证你的想法~~
int03h
int03h
1然后,我又测试了一下。。。
# PATH= ls
-bash: ls: 没有那个文件或目录
#PATH= echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
一瞬间,我明白了。这并没有清变量,只是令环境变量在那一行无效化。。。
shell:读取文件的每一行内容并输出

本文原创于:http://www.cnblogs.com/iloveyoucc/archive/2012/07/10/2585529.html shell:读取文件的每一行内容并输出 写法一: --------------------------------------------------------......

love8023icando
2016/09/06
0
0
IO重定向与文件描述符

1.介绍 IO重定向用于捕捉一个文件,命令,程序,脚本或者代码块的输出,然后把捕捉到的输出作为输入发送给另外一个文件,命令,程序或脚本。 终端程序一般从单一源以流的形式聚集输入和显示输...

adelphos
2015/01/02
0
0
嵌入文档——here document

配置文件 cat< file.config write your config here EOF Here Documents的一般形式如下: 0001 commands < 0002 here documents ....... ...... 000n ID<n> 在上面这个语法描述中,0001行的c......

xiangxw
2010/12/21
0
0
Linux Shell常用技巧(十二) Shell编程

二十三. Bash Shell编程: 1. 读取用户变量: read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入。在read命令后面,如果没有指定变量名,读...

长平狐
2012/08/27
264
0
Linux Shell常用技巧(十二) Shell编程

二十三. Bash Shell编程: 1. 读取用户变量: read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入。在read命令后面,如果没有指定变量名,读...

长平狐
2012/09/06
77
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

RabbitMQ在CentOS环境安装

1.废话不多说准备一台虚拟机,系统为centos,我这里使用的系统版本如下图所示:

凌晨一点
44分钟前
0
0
线程池相关

在java.util.concurrent包下,提供了一系列与线程池相关的类。 使用线程池的好处 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗; 提高响应速度。当任务到达时,任务...

edwardGe
46分钟前
0
0
学习大数据这三个关键技术是一定要掌握!

大数据时代全面来临,大数据、人工智能等技术引领科技创新潮流,获得国家政策大力支持,前景广阔。学习大数据技术的人自然是络绎不绝, 学习大数据虽然是一个趋势,但也要注意大数据培训课程...

董黎明
今天
0
0
jetbrains 上传代码到github

设置中找github 获取token 验证是否成功 测试git 生成key,一路回车即可 ssh-keygen -t rsa -C “youremail@example.com” 打开pub复制key,需要再次输入一次密码 验证是否成功,输入yes即可...

阿豪boy
今天
0
0
分布式服务框架(拾遗)

前言 现在的大部分工程都已经是基于分布式架构来处理。所以这里对分布式框架做一个简单的总结 常用的RPC框架 RPC框架原理 RPC(Remote Procedure Call,远程过程调用)一般用来实现部署在不同...

kukudeku
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部