如何使用 awk 进行数字比较并创建列表 - 在 macOS 上使用带有 CRLF 行结尾的 Awk

how to use awk to do a number comparisons and create a list - using Awk on macOS with CRLF line endings

我试图列出比我列出的值更大的值(来自我的 knife 命令的输出)。我正在尝试使用 awk 来做到这一点,我一直在研究示例并想出了这个。但是,我的预期输出不起作用。

例如,使用此命令,我得到以下输出:

knife ssh -x foobar -a ec2.local_ipv4 "chef_environment:prod AND roles:db_cluster AND AND ipaddress:10.1.*" 'netstat -na | grep EST | wc -l'

输出:

10.1.3.129 2273
10.1.3.130 2533
10.1.3.131 1981
10.1.2.133 1965

现在,我想使用 awk,因为我只想过滤那些值(第 2 列,删除 IP)> 2000。

我尝试了以下 awk 语句,但无济于事

knife ssh -x foobar -a ec2.local_ipv4 "chef_environment:prod AND roles:db_cluster AND AND ipaddress:10.1.*" 'netstat -na | grep EST | wc -l' \
| awk '{if ( > 2000) print ; else echo "Nothing to print"}`

输出:

10.1.3.129 2273
10.1.3.130 2533
10.1.3.131 1981
10.1.2.133 1965

预期输出:

2273
2533

tl;dr

最简单的方法是在将输出传递给 awk 之前从输出中删除 \r 个实例:

knife ... | tr -d '\r' | awk ...

这假设 \r 个实例仅作为 \r\n 对的一部分出现以指定行结尾,通常情况就是如此。


根据您的评论,我们现在知道您的输入具有 Windows 样式的 CRLF (\r\n) 行结尾 并且您在 macOS Sierra (10.12).

也就是说,您的样本输出与您问题中的 awk 命令不一致。

撇开这个问题不谈,有两种基本方法

  • (a) 将 \r\n (CRLF) 序列翻译成 \n (LF) first

  • (b) 通过修改 Awk 的输入记录分隔符解决此问题。


以下示例使用简化的输入和简化的命令来关注核心问题:

  • printf '10.1.3.129 2273\r\n10.1.3.130 2533\r\n' 用于生成 2 个以 CRLF 终止(\r\n 终止)的输入行,每个行包含 2 个以空格分隔的字段。

  • awk '{ print }' | cat -e - 或其变体 - 使用 awk 从每行打印第二个空格分隔的字段,并且 cat -e 用于可视化控制字符在输出中:$ 表示 \n (LF) 字符。 (Unix 术语中的行尾),其他控制字符可视化为 ^<letter>,即 caret notation;因此,\r (CR) 表示为 ^M.

    • 默认情况下,\r 包含在输出中 ,因为 awk 不认为它是空白(这些行被分割成字段) - 这显然是不希望的。输出如下所示,其中 ^M 表示不希望包含的 \r:

      2273^M$
      2533^M$
      
    • 使用有效的解决方案,\r 不包含在输出中, 输出如下所示(注意没有^M):

      2273$
      2533$
      

基于方法 (a) 的解决方案:

通常,实用程序 dos2unix 用于将 Windows 风格的换行符转换为 Unix 风格的换行符,但该实用程序不会出现使用 macOS。
但是,通过 Homebrew 很容易安装它。
然后使用 knife ... | dos2unix | awk ....
(或者先将输出发送到文件并在进一步处理之前就地更新该文件:dos2unix file。)

或者无耻自夸部给你带来的,你可以安装我的nws CLI如果你安装了Node.js,安装它通过简单地 运行 [sudo] npm install -g nws-cli 然后使用 knife ... | nws --lf | awk ....
(或者,先将输出发送到文件并在进一步处理之前就地更新该文件:
nws --lf -i file; nws 还可以将 LF 转换为 CRLF,并提供其他与空格相关的功能。)

还有一些相当简单的方法可以使用常用的 macOS 实用程序 - 请参阅我的 this answer

最简单的库存实用程序解决方案是使用 tr 盲目删除任何 \r 个实例:

$ printf '10.1.3.129 2273\r\n10.1.3.130 2533\r\n' |
    tr -d '\r' | awk '{ print  }' | cat -e
2273$
2533$

基于方法 (b) 的解决方案:

$ printf '10.1.3.129 2273\r\n10.1.3.130 2533\r\n' |
    awk -v RS='\r' 'NF {print }' | cat -e
2273$
2533$

请注意 -v RS='\r' 如何将 \r 定义为 RS,输入记录分隔符,这意味着它会自动从 awk 的每个记录(行)中排除读取并拆分为字段。

NF,作为 条件 放置在操作 ({...}) 之前是必要的,以消除读取最终 [= 产生的空行22=]作为单独的记录。

  • 如果我们可以RS定义为\r\n,这可以避免,但是,遗憾的是,macOS 上的 BSD Awk 不支持多-字符输入记录分隔符(符合POSIX spec.).
    然而,通过 Homebrew,你可以安装 GNU Awk,它支持这样的分隔符,这将简化命令为:
    gawk -v RS='\r\n' '{print }'