如何从 awk $NF 列中删除 CRLF

Ken*_*ram 1 bash awk shell-script

我不知道如何表述这个问题,因为大多数答案都是关于\r\n从文件中删除的。

我有一个独特的问题,压缩文件是随机编号的,为了将它们与数据库记录正确关联,我需要列出文件内容并检查它们。

我正在使用此解决方案 “在 bash 脚本中,如何逐行捕获标准输出”

这是一个很好的开始。

某些内容的名称带有空格,我找到了这个解决方案: 如何将第三列打印到最后一列?

我在尝试更新数据库记录时发现,它^M被插入到awk管道的结果中,但仅限于NF列。

不知道如何解决这个特殊的故障。我没有看到^M插入的位置,或者如何从最后一列中删除它。

我的代码

如果我剥离,这条线工作正常 ^M

filename="$(echo "$line" | awk '{if ($3 ~ /^M$/) {sub(/^M$/,"", $3)} printf $3; printf ""}')"
Run Code Online (Sandbox Code Playgroud)

此行失败:

text="$(echo "$line" | awk '{for(i=6;i<NF+1;i++) {if ($i ~ /^M$/) {sub(/^M$/,"", $i)} } printf "%s ", $i; printf ""}')"
Run Code Online (Sandbox Code Playgroud)

简化版失败了:

text="$(echo "$line" | awk '{for(i=6;i<NF+1;i++) sub(/^M$/,"", $i) printf "%s ", $i; printf ""}')"
Run Code Online (Sandbox Code Playgroud)

vim/vi ^Mctrl-V + <return key> 使用 Using创建\r\n无效。

我正在使用cygwin,并且已经使用了很长时间,并且我*nix编写了其他运行良好的脚本。我发现由于某种原因,这个特殊的运行awk正在添加^M到输出中。

我发现这个问题有一个类似的问题,但我vim从一开始就创建了我的脚本,所以没有涉及基于 Windows 的编辑器。

如果我将该 windows 文件夹安装为 samba 共享并从 linux 运行脚本,它会产生没有 . 的输出^M,所以此时我想知道这是一个错误还是其他什么。这真的很奇怪。

更新 我在 sub() 中使用 REGEX 导致字符串返回空,所以我没有正确理解如何清除 CRLF。

NF+1 是我尝试找出引入 CRLF 之前我使用的 i<=NF 的剩余部分。

Sté*_*las 5

除了少数的实现awk,包括GNU awkmawk和busybox的awk(3个实现通常基于Linux系统中,Cygwin的是GNUawk默认情况下,我相信),RS输入记录分隔符可以是正则表达式(而不是在POSIX单个字符) .

在那些中,您可以执行以下操作:

awk -v RS='\r\n' '{print $NF}' < your-file.msdos
Run Code Online (Sandbox Code Playgroud)

处理这些文件,或:

awk -v RS='\r?\n' '{print $NF}' < your-file.msdos-or-unix
Run Code Online (Sandbox Code Playgroud)

能够使用\n分隔符或\r\n分隔符处理这两个文件。

一些 MS-DOS 文件的最后一行也往往没有分隔,但awk也会在输出时修复它,因为它在打印时将输出记录分隔符(ORS保留\n在此处)附加到所有记录。

就默认字段拆分而言awk,您还会发现实现之间存在差异。POSIX 说它应该在空白序列上拆分,删除前导和尾随。空白的概念取决于区域设置,并且至少包括 SPC 和 TAB。您会发现许多awk实现仅将其限制为 SPC 和 TAB,而不管语言环境如何,许多实现还添加了 NL(仅当记录分隔符不是换行符时才相关)。

busyboxawk 包括所有 ASCII 空格,因此包括CR, FF, VT. 所以在 busybox 中awk,字段默认从不包含 CR。您可以awk通过将gawk -v 'FPAT=[^[:space:]]'其中的字段定义为非空白序列来实现与 GNU 相同的行为。

还有一些注意事项:

  • 避免使用 shell 循环来处理文本,尤其是在这里,因为您已经在使用awk它是处理文本的正确工具之一。
  • 不要echo在任意数据上使用
  • 第一个参数printf是格式,你不想在那里使用任意数据。使用printf "%s", $3,如果你要打印$3而不附加ORS,没有printf $3
  • printf ""是一个空操作。它什么也不做。如果要打印换行符,请使用printf "\n"print ""(后者ORS默认打印, 换行符)。

  • 请注意 `RS='\r?\n'` 因为某些文件,例如从 MS-Excel 导出的 CSV,将使用 `\r\n` 作为记录的结尾,但使用 `\n` 作为换行符在字段内,所以如果你设置 `RS='\r?\n'` 那么你会像读取整个记录一样读取部分记录,因为字段内的 `\n` 也将被解释为记录。 (2认同)