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