shell 脚本中的奇怪 "echo" 行为
Strange "echo" behavior in shell script
我想这样打印数组拆分得到的内容:
string="abc test;ABCtest.it"
IFS=';' read -a array <<< "$string"
name="${array[0]}"
url="${array[1]}"
echo -ne "\n$url,$name" >> "$outputDir/$fileName"
但是输出文件不包含 URL 部分。
我认为问题出在 .
,但我不知道如何解决它。
如果我试试这个
echo $url
有效!
我也尝试过 printf
和硬编码文件名,但没有!
printf '%s %s\n' "$url" "$name" >> test.txt
似乎当我尝试在变量 $url
之后连接另一个东西时,变量的某些部分被删除或覆盖到输出文件中。
例如,如果我尝试这样做:
printf '%s %s\n' "$url" "pp" >> test.txt
我用一个简单的 cat test.txt
得到的是这样的:
pptest.it
但是变量$url
的内容必须是ABCTest.it
.
试试这个:
echo -ne "\n""$url"",$name" >> "$outputDir/$fileName"
不知何故,$string
的值以回车符 return 结尾。你实际回应的是
echo -ne "\nABCtest.it\r,abc test"
回车 return 导致光标移动到当前行的开头,然后打印其后的文本,覆盖 url。用
删除马车 return
string=${string#?}
或首先修复 string
的设置方式(我怀疑您正在读取使用 DOS 行尾的文件,在这种情况下,您可以使用 dos2unix
转换文件。)
补充:
如果输出看起来你期望的样子,它总是worth 检查其内容以寻找隐藏的控制字符可能会改变数据的外观输出.
\r
,一个 CR(回车 return;ASCII 值 13)是一个臭名昭著的例子,原因有两个:
- (正如@chepner 所说)它将光标移动到行中间字符串的开头,有效地删除了至少一部分之前的内容;例如。:
echo $'abcd\refg'
打印 efgd
:\r
导致之后的所有内容在行首重新开始打印,只有字符串 [=54] 中的 d
=]before \r
幸存下来,因为它 恰好是 1 个字符。长于 after.
之后的字符串
(注意:$'...'
语法是所谓的 ANSI C-quoted string,它允许使用转义序列,例如 $'...\r...'
中的 \r
来创建 actual 控制字符。)
- 包含意外
\r
个字符的文件。在与 Windows 世界交互时经常发生,其中换行符不仅仅是 \n
个字符,而是 \r\n
个序列,并且此类文件在 Unix 世界中表现得很奇怪。
- 一种 检查数据的简单方法是将其通过管道传输到
cat -et
,它将控制字符突出显示为 ^<char>
序列:
^M
表示一个\r
(CR)
^I
表示一个 \t
(tab.char)
^[
表示一个ESC字符。
... # see 'man cat'
- 行尾表示为
$
- 因此,具有 Windows 样式行尾的文件将在
cat -et
输出的行末尾显示 ^M$
。
cat -et
应用于上面的示例会产生以下结果,这使得诊断问题变得容易:
echo $'abcd\refg' | cat -et # -> 'abcd^Mefg$' - note the ^M
dos2unix
是 将 Windows 样式的行尾 (\r\n
) 转换为 Unix 行尾 (\r\n
),但大多数类 Unix 平台上并未预装此工具,并且 易于使用标准 POSIX 实用程序 来执行此类转换:
awk 'sub("\r$", "")+1' win.txt > unix.txt
- 请注意,此 POSIX 兼容命令不允许您 就地 替换文件,但是:
- 如果您有 GNU
sed
,以下将执行 就地 的转换:
sed -i 's/\r$//' winIn_UnixOut.txt
- 同上 BSD
sed
(也用于 OSX),来自 bash
, ksh
, 或 zsh
:
sed -i '' $'s/\r$//' winIn_UnixOut.txt
我想这样打印数组拆分得到的内容:
string="abc test;ABCtest.it"
IFS=';' read -a array <<< "$string"
name="${array[0]}"
url="${array[1]}"
echo -ne "\n$url,$name" >> "$outputDir/$fileName"
但是输出文件不包含 URL 部分。
我认为问题出在 .
,但我不知道如何解决它。
如果我试试这个
echo $url
有效!
我也尝试过 printf
和硬编码文件名,但没有!
printf '%s %s\n' "$url" "$name" >> test.txt
似乎当我尝试在变量 $url
之后连接另一个东西时,变量的某些部分被删除或覆盖到输出文件中。
例如,如果我尝试这样做:
printf '%s %s\n' "$url" "pp" >> test.txt
我用一个简单的 cat test.txt
得到的是这样的:
pptest.it
但是变量$url
的内容必须是ABCTest.it
.
试试这个:
echo -ne "\n""$url"",$name" >> "$outputDir/$fileName"
不知何故,$string
的值以回车符 return 结尾。你实际回应的是
echo -ne "\nABCtest.it\r,abc test"
回车 return 导致光标移动到当前行的开头,然后打印其后的文本,覆盖 url。用
删除马车 returnstring=${string#?}
或首先修复 string
的设置方式(我怀疑您正在读取使用 DOS 行尾的文件,在这种情况下,您可以使用 dos2unix
转换文件。)
补充
如果输出看起来你期望的样子,它总是worth 检查其内容以寻找隐藏的控制字符可能会改变数据的外观输出.
\r
,一个 CR(回车 return;ASCII 值 13)是一个臭名昭著的例子,原因有两个:- (正如@chepner 所说)它将光标移动到行中间字符串的开头,有效地删除了至少一部分之前的内容;例如。:
echo $'abcd\refg'
打印efgd
:\r
导致之后的所有内容在行首重新开始打印,只有字符串 [=54] 中的d
=]before\r
幸存下来,因为它 恰好是 1 个字符。长于 after.
之后的字符串 (注意:$'...'
语法是所谓的 ANSI C-quoted string,它允许使用转义序列,例如$'...\r...'
中的\r
来创建 actual 控制字符。)
- 包含意外
\r
个字符的文件。在与 Windows 世界交互时经常发生,其中换行符不仅仅是\n
个字符,而是\r\n
个序列,并且此类文件在 Unix 世界中表现得很奇怪。
- (正如@chepner 所说)它将光标移动到行中间字符串的开头,有效地删除了至少一部分之前的内容;例如。:
- 一种 检查数据的简单方法是将其通过管道传输到
cat -et
,它将控制字符突出显示为^<char>
序列:^M
表示一个\r
(CR)^I
表示一个\t
(tab.char)^[
表示一个ESC字符。... # see 'man cat'
- 行尾表示为
$
- 因此,具有 Windows 样式行尾的文件将在
cat -et
输出的行末尾显示^M$
。
cat -et
应用于上面的示例会产生以下结果,这使得诊断问题变得容易:echo $'abcd\refg' | cat -et # -> 'abcd^Mefg$' - note the ^M
dos2unix
是 将 Windows 样式的行尾 (\r\n
) 转换为 Unix 行尾 (\r\n
),但大多数类 Unix 平台上并未预装此工具,并且 易于使用标准 POSIX 实用程序 来执行此类转换:awk 'sub("\r$", "")+1' win.txt > unix.txt
- 请注意,此 POSIX 兼容命令不允许您 就地 替换文件,但是:
- 如果您有 GNU
sed
,以下将执行 就地 的转换:sed -i 's/\r$//' winIn_UnixOut.txt
- 同上 BSD
sed
(也用于 OSX),来自bash
,ksh
, 或zsh
:sed -i '' $'s/\r$//' winIn_UnixOut.txt
- 如果您有 GNU