为什么行终止符会更改此 Bash 脚本的输出?

M J*_*son 2 shell bash shell-script

在调试脚本时,我终于找到了原因,但我不明白为什么。

一个制表符分隔的文本文件示例包含:

$ cat list1.txt
123 Fake St Miami   FL
456 None Rd San Francisco CA
789 Nowhere Dr  Denver  CO
Run Code Online (Sandbox Code Playgroud)

最初使用 vi 创建,文件将其标识为

$ file list1.txt
list1.txt: ASCII text
Run Code Online (Sandbox Code Playgroud)

运行这一行(编辑:将帖子更改为多行以提高可读性)将每一行读入 3 个变量,打印顺序如脚本中指定。请注意,字符串的连接非常复杂,因为我在调试时试图非常明确地说明顺序:

$ while IFS="     " read -r addr1 city state
do
  data0="'"
  data1='companyName=&'
  data2="address1=$addr1"
  data3='&city='
  data4="$city"
  data5='&state='
  data6="$state"
  data7='&urbanCode=&zip='
  data8="'"
  data=${data0}${data1}${data2}${data3}${data4}${data5}${data6}${data7}${data8}
  echo "$data"
done < list1.txt

'companyName=&address1=123&city=Fake&state=St   Miami   FL&urbanCode=&zip='
'companyName=&address1=456&city=None&state=Rd   San Francisco CA&urbanCode=&zip='
'companyName=&address1=789&city=Nowhere&state=Dr    Denver  CO&urbanCode=&zip='
Run Code Online (Sandbox Code Playgroud)

更改文件 list1.txt DOS 格式会导致输出重新排序

$ unix2dos list1.txt
unix2dos: converting file list1.txt to DOS format...
$ file list1.txt
list1.txt: ASCII text, with CRLF line terminators
$ while IFS="     " read -r addr1 city state; do  data0="'";  data1='companyName=&';  data2="address1=$addr1";  data3='&city=';  data4="$city";  data5='&state=';  data6="$state";  data7='&urbanCode=&zip=';  data8="'";  data=${data0}${data1}${data2}${data3}${data4}${data5}${data6}${data7}${data8};  echo "$data"; done < list1.txt
&urbanCode=&zip='ress1=123&city=Fake&state=St   Miami   FL
&urbanCode=&zip='ress1=456&city=None&state=Rd   San Francisco CA
&urbanCode=&zip='ress1=789&city=Nowhere&state=Dr    Denver  CO
Run Code Online (Sandbox Code Playgroud)

为什么会发生这种情况?GNU bash,版本 3.2.57

Kus*_*nda 6

当从 DOS 格式的文本文件中读取一行到三个变量中时,最后一个变量state将以回车符结尾。这是因为 DOS 文本文件使用字符序列 CR+LF(回车后换行)表示“换行”。Unix 文本文件仅使用换行符换行,DOS 文本文件的回车符被视为行尾的任何其他字符。

当输出$state到终端时,这个回车符使输出的位置跳到行首(这就是回车符的目的,返回“回车”(行式打印机的,曾经时间)到行的开头)并将以下字符串放置在行的最开头,覆盖以前在终端中这些位置输出的任何文本。

所以你会得到第一行,

'companyName=&address1=123&city=Fake&state=
Run Code Online (Sandbox Code Playgroud)

$state后跟,的值St Miami FL,然后光标返回到行的开头,其中

&urbanCode=&zip='
Run Code Online (Sandbox Code Playgroud)

输出,覆盖该行的第一部分,导致看起来很奇怪

&urbanCode=&zip='ress1=123&city=Fake&state=St   Miami   FL
Run Code Online (Sandbox Code Playgroud)

  • @MJohnson在我的回答中,我说首先打印“companyName=&amp;address1=123&amp;city=Fake&amp;state=”,然后打印“St Miami FL”。然后光标返回到行的开头,并且 `&amp;urbanCode=&amp;zip='` 会覆盖之前在行开头的内容。这正是所发生的情况,并且结果正是您运行代码时所看到的。 (2认同)