我需要将文件读入数组并在每行的末尾连接一个字符串。这是我的bash脚本:
#!/bin/bash
IFS=$'\n' read -d '' -r -a lines < ./file.list
for i in "${lines[@]}"
do
tmp="$i"
tmp="${tmp}stuff"
echo "$tmp"
done
但是,当我执行此操作时,会发生replace
的操作,而不是连接。
例如,在file.list
中,我们有:
http://www.example1.com
http://www.example2.com
我需要的是:
http://www.example1.comstuff
http://www.example2.comstuff
但是在执行上面的脚本后,我在终端上得到如下内容:
stuff//www.example1.com
stuff//www.example2.com
不过,我的电脑是Mac OS。
答案 0 :(得分:4)
文件./file.lst
很可能是在Windows系统上生成的,或者至少是使用Windows约定保存为行尾。
Windows使用两个字符的序列来标记文本文件中的行尾。这些字符为CR
(\r
),后跟LF
(\n
)。类Unix系统(从版本10开始的Linux和macOS)使用LF
作为行尾字符。
代码中IFS=$'\n'
前面的作业read
告诉read
使用LF
作为行分隔符。 read
不会将LF
字符存储在其生成的数组中(lines[]
),但lines[]
中的每个条目都以CR
字符结尾。< / p>
行tmp="${tmp}stuff"
执行它应该做的事情,即它将单词stuff
附加到变量tmp
的内容(从文件读取的行)。
从输入文件读取的第一行包含字符串http://www.example1.com
,后跟CR
字符。附加字符串stuff
后,变量tmp
的内容为:
http://www.example1.com$'\r'stuff
CR
字符无法打印。它在终端上打印时有一个特殊的解释:它在行的开头(第1列)发送光标而不改变行。
当echo
打印上面的行时,它会打印(从新行开始)http://www.example1.com
,然后是CR
字符,它将光标发送回行的开头。打印字符串stuff
。 stuff
片段会覆盖已在该行(http:
)上打印的前5个字符,并且结果(因为它在屏幕上可见)为:
stuff//www.example1.com
解决方案是从输入文件中删除CR
个字符。有几种方法可以实现这一目标。
从输入文件中删除CR
字符的一种简单方法是使用命令:
sed -i.bak s/$'\r'//g file.list
它会从文件CR
的内容中删除所有file.list
个字符,将更新后的字符串保存回file.list
文件,并将原始file.list
文件存储为{{ 1}}(备份副本,以防它没有产生您期望的输出)。
摆脱file.list.bak
字符的另一种方法是让shell在附加CR
的命令中将其删除:
stuff
在tmp="${tmp/$'\r'/}stuff"
之类的构造中展开变量时,${tmp/a/b}
中a
的所有外观都会被$tmp
替换。在这种情况下,我们无需替换b
。
答案 1 :(得分:2)
我猜它与Carriage Return字符有关。
您的file.list
是否在Windows上创建了?如果是这样,请在运行脚本之前尝试使用dos2unix
。
修改强>
您可以使用file
命令检查文件。
示例:
file file.list
如果您在Windows记事本中保存文件,请执行以下操作:
然后它可能会出现这样:
file.list: ASCII text, with no line terminators
您可以使用iconv
之类的内置工具来转换编码。但是,对于这样的简单用法,您只需使用适用于多种编码的命令,无需任何转换。
您可以简单地通过cat
缓冲文件,并使用适用于以下任一项的正则表达式:
然后追加字符串。
示例:强>
cat file.list | grep -E -v "^$" | sed -E -e "s/(\r?$)/stuff/g"
将使用ASCII文本和没有行终止符的ASCII文本。
答案 2 :(得分:0)
如果您需要修改流以附加固定字符串,则可以使用sed
或awk
,例如:
sed 's/$/stuff/'
将东西附加到每行的末尾。