读取一个文件并复制到另一个文件

读取一个文件并复制到另一个文件

我遇到了问题,我需要复制文件内容并删除几行(如果它们与上一个命令的输出匹配)。但到目前为止,我在保持文件行完全相同方面遇到了问题。我将脚本的简单部分作为 if 省略副本不是问题的一部分,因为这种情况发生在未受影响的行上。

例如:

在原始文件中我有以下内容

Testing,      resuming text

运行脚本时,字段变为:

Testing, resuming text

我正在执行以下操作:

#!/usr/bin/bash
rm /tmp/dest_file
while read line
do
   echo $line >> /tmp/dest_file
done < $1

我遇到的问题是,由于制表符格式的字段,文件会变得不同。

答案1

这个网站已经出现过好几次了——参见了解 IFS以及相关问题。在这个答案中,我将总结什么可能会出错以及如何避免它;有关详细信息,请参阅链接的线程。

read line执行以下操作:

  1. 从标准输入读取第一个字节(换行符或空值),并将数据放入名为 的变量中line
  2. 去掉不在行尾的任何反斜杠。双反斜杠\\变成单反斜杠。换句话说,反斜杠引用下一个字符,只要它不是换行符。
  3. 如果read停在换行符处并且该行末尾的字符是 a \,则去除反斜杠换行符序列并继续读取,附加到变量line。重复直到第一个: 前面没有反斜杠的换行符;一个空字节;输入结束。
  4. line去掉由 中的字符组成的最长后缀$IFS。默认情况下,IFS包含一个制表符、一个空格和一个换行符,因此这会从 值的末尾去除 ASCII 空格line
  5. line去掉中由空格字符组成的最长前缀$IFS

例如,如果输入是

 : hello\
world: :
wibble

然后read line导致line包含: helloworld: :(无初始空间),默认值为IFS。如果IFS已更改为:(仅一个冒号),则read line结果为 : helloworld: (开头和结尾都有一个空格)。如果IFS同时包含:和 一个空格,则结果为: helloworld(无初始或尾随空格)。

为了避免 的影响IFS,请将其设置为空值(注意这与取消设置不同)。您只能read通过编写命令来设置它IFS= read(请参阅为什么如此频繁地使用“while IFS= read”,而不是“IFS=;”在阅读时..`?)。

为了避免反斜杠处理,请将-r选项传递给read.

除非 shell 是 zsh,否则如果输入中存在空字节,则后续字符将丢失。 Shell 并非设计用于读取二进制数据。

因此,一次读取一行的习惯用法是:

while IFS= read -r line; do
  … # process "$line"
end

当您使用变量时line,请确保总是在变量替换两边加上双引号: "$line"。如果没有双引号,shell 首先扩展变量的值,然后在包含来自 的字符的地方将该值分解为单独的单词IFS,并且每个单词都被解释为通配符模式并替换为匹配文件的列表(如果没有匹配文件,模式保持原样)。因此扩展到当前目录中以或echo 'a* b*' | IFS= read -r line; echo $line开头的文件列表;要使输入保持不变,请使用.abecho 'a* b*' | IFS= read -r line; echo "$line"

另请注意,该echo命令有时会修改它打印的字符串。确切的方式取决于 shell。有些 shell 处理反斜杠转义,有些 shell 识别选项。echo仅当您知道该字符串不包含任何反斜杠且不以破折号 ( -)开头时,才能逐字输出字符串。一种按原样打印字符串的可靠且便携的方法

printf '%s\n' "$line"

这会在字符串后打印一个换行符,例如echo.您可以通过\n在上面的命令中省略来省略换行符。

答案2

引用你的变量:

echo "$line" >> /tmp/dest_file

相关内容