String Bash:Can';t将字符串附加到现有字符串-它似乎会覆盖该字符串的开头

String Bash:Can';t将字符串附加到现有字符串-它似乎会覆盖该字符串的开头,string,bash,line-endings,String,Bash,Line Endings,这是一个帮助我们创建dhcpd.conf文件的脚本 示例输入(例如mac选项卡-;-选项卡IP) 预期产出 Host 27-48 { hardware ethernet DC:D3:21:75:61:90 ; fixed-address 10.25.131.17 ; } #host 27-48 { hardware ethernet ; fixed-address ; } 当前输出的行如下所示: Host 27-48 { hardware ethernet 00:16:6B:C8:3D:C9

这是一个帮助我们创建dhcpd.conf文件的脚本

示例输入(例如mac选项卡-;-选项卡IP)

预期产出

Host 27-48 { hardware ethernet DC:D3:21:75:61:90 ; fixed-address 10.25.131.17 ; }

#host 27-48 { hardware ethernet ; fixed-address ; }
当前输出的行如下所示:

Host 27-48 { hardware ethernet 00:16:6B:C8:3D:C9 ; fixed-address 10.25.129.185
代码中的特定行我被卡住了

outputLine="Host $((names[i]))-$((startingNumber+counter)) { hardware ethernet $first ; fixed-address $second"
如果我尝试添加;}

outputLine="Host $((names[i]))-$((startingNumber+counter)) { hardware ethernet $first ; fixed-address $second ; }"
我明白了:

; } 27-48 { hardware ethernet 00:16:6B:C8:3D:C9 ; fixed-address 10.25.129.185
问题是,每当我将“;}”附加到上述行的末尾时,它都会覆盖该行的开头。我尝试了一些技巧来解决这个问题,例如将上面的行写入字符串,然后尝试附加到字符串,但同样的问题也发生了。我有一个想法,将整个内容导出到一个文件中,然后将文件重新加载到一个数组中,这样我就可以追加,但这似乎有点过分了

for ((j=1; j<=${sizes[i]}; j++ )); do

    #split line, read split as two entries for an arrIN
    IN=(${line[counter+1]})
    arrIN=(${IN//;/ })
    first="${arrIN[0]}"
    second=${arrIN[1]}


    if [ ${lineSize[counter+1]} -gt 5 ]
    then
        #sed 's/$/ ; }/' $outputLine > newoutputLine
        outputLine="Host $((names[i]))-$((startingNumber+counter)) { hardware ethernet $first ; fixed-address $second"
        echo $outputLine
    else
        echo "#host $((names[i])) $((startingNumber+counter)) { hardware ethernet ; fixed-address ; }"
    fi
    counter=$((counter+1))
done
((j=1;j newoutputLine)的

outputLine=“主机$((名称[i])-$((起始编号+计数器)){硬件以太网$第一;固定地址$第二”
echo$输出线
其他的
echo“#主机$((名称[i]))$((启动号+计数器)){硬件以太网;固定地址;}”
fi
计数器=$((计数器+1))
完成
正如在对该问题的评论中所解释的那样,问题是变量
$second
值末尾的一个CR(
0xD
\r
)字符,该字符可以通过以下方式删除:
second=“${second/$'\r'/}”

本答案的其余部分解释了症状并提供了背景信息


问题是,每当我将“;}”附加到上述行的末尾时,它都会覆盖该行的开头

“覆盖行首”几乎总是指向嵌入的(
0xD
\r
)字符
,当字符串打印到终端时,该字符显示为覆盖行首:

$ printf 'abc\rd'  # `printf '\r'` produces a CR 
dbc  # It LOOKS LIKE 'd' replaced 'a', but that's an artifact of printing to the terminal.
仅因为终端将CR(
\r
)解释为“将光标放在行的开头”,所以
d
-在
\r
之后的剩余字符串-显示为“覆盖”字符串已打印部分的开头

您可以使用
cat-et
可视化嵌入的CRs(和其他控制字符),将它们表示为
^M

$ printf 'abc\rd' | cat -et
abc^Md   # ^M represents a CR (\r)
如您所见,
d
实际上并没有覆盖字符串开头的
a


CR(
\r
)实例在Unix文本处理领域中很少使用。如果它们确实作为文本数据的一部分出现,则通常来自使用CRLF(
\r\n
)行结尾的Windows源,而不是仅使用Unix LF(
\n
)行结尾。

通常,最简单的方法是在将数据与Unix实用程序一起使用之前删除CR(
\r
)实例

有许多现有答案涵盖了这一领域,通常建议使用第三方实用程序,可通过许多平台的软件包管理器轻松安装(例如,Ubunutu上的
sudo apt install dos2unix
,或macOS上的
brew install dos2unix
,via)

或者

  • 对于已经存储在变量中的文本,使用基于参数扩展的方法;例如,
    second=“${second/$'\r'/}”

  • 对于文件,可以充当临时的
    dos2unix


试着打印
$second
——可能在
${arrIN[1]}的结尾有一些有趣的东西
清楚地说明您的输入变量,并提供准确的预期输出。您的
bash
代码是创建
dhcpd.conf
文件,还是只想在末尾使用
;}
对该文件进行适当编辑?更新的示例输入。bash代码不是创建dhcpd.conf,而是创建最终将被合并的一部分使用子网部分(即复制和粘贴)。已经提供了一个输出,将更新另一个“空格”的输出。必须有回车符潜入(即,您的输入必须有Windows行结尾)。请尝试运行,例如,
second=“${second/$'\r'/}”
将其剪下。输入是excel中的列,粘贴到记事本或记事本++中。我会试试看,谢谢。可能就是这样。编辑:就是这样!非常感谢!如果您将此作为答案添加,我将对其进行投票。我认为这是一个“特殊字符”问题。
$ printf 'abc\rd' | cat -et
abc^Md   # ^M represents a CR (\r)