【问题标题】:bash: how to delete last symbolbash:如何删除最后一个符号
【发布时间】:2013-01-11 10:57:28
【问题描述】:

我正在尝试从 bash 命令输出中提取一些信息:

uptime | awk '{print $3}'

运行时我得到这个结果:8:27,

如何删除最后一个符号(即逗号)?

【问题讨论】:

  • 在您的机器上发布“uptime”的输出以及您希望从脚本中获得的预期最终输出,以便我们为您提供最佳答案
  • @EdMorton 请参阅my anwser 了解uptime 的不同输出。

标签: bash shell awk


【解决方案1】:

另一种变体(将awksed 替换为cut):

# "unnecessary" echo with evil backticks to get rid of extra spaces
echo `uptime|cut -d, -f1'

似乎可以工作...直到正常运行时间达到一天(感谢@sudo_O 指出)。然后输出格式会包含天数,我们需要

echo `uptime|cut -d, -f2`

(后者是我最初的答案,因为我测试的正常运行时间 > 24 小时)。

UPD:这两种解决方案都不起作用:后者打印没有天数的正常运行时间,前者无法提取小时数,因为没有天数时它们前面没有逗号分隔符 - 但答案的其余部分实际上是这些失败证明了。

整个方法容易出错。几个月和几年后会发生什么? (我似乎记得它仍然显示 N 天,但我可能会出错)。如果正常运行时间是本地化的怎么办? (他们是否因为现有脚本而拒绝这样做?)它为 1 个用户、“1 个用户”或“1 个用户”显示了什么?如果我们知道所有的答案,我们还想依赖它们吗?

如果我们的目的是向用户显示正常运行时间,使用正则表达式提取“up”和“users”之间的部分就可以了:

uptime | sed 's/^.*up\(.*\), *[0-9]\+ *users.*$/\1/'

如果我们想比较时间或收集统计数据,类似 Linux 特定的 /proc/uptime 会更好(/proc/uptime 中的第一列是原始正常运行时间秒数)。

【讨论】:

  • 结果:5 users. suse12.2
  • 这是如何获得 4 个赞成票的,这是不正确的,因为它会打印错误的结果,并且完全不需要回显。
  • awksed 在同一台机器上会更好吗?顺便说一句,我更喜欢 Linux 上 /proc/uptime 的第一个值。
  • @sudo_O echo+backquotes 删除空格。并且它并不比所有答案和最初的想法更“不正确”,当正常运行时间输出格式包含/省略“最多 N 天”时(我的变体在存在天数时“有效”),所有这些都被破坏了。
  • @sudo_O 虽然我完全同意应该使用$() 表示法而不是反引号的观点,但反引号 命令替换。它们只是可怕的语法。
【解决方案2】:

您几乎拥有它,只是带有awksubstrgsub 函数

$ uptime | awk '{print substr($3,1,length($3)-1)}'
2:49

$ uptime | awk '{sub(/,/,"");print $3}'
2:49

不需要过多的管道或不正确地使用反引号。

uptime 使用 (GNU) grep -Po "\d{1,2}:\d{2}(?=,)" 的不同输出的情况下,提供了更好但更强大的解决方案:

# More than one day    
$ uptime
12:46:18 up 92 days,  5:00,  2 users,  load average: 0.00, 0.01, 0.05
$ uptime | grep -Po "\d{1,2}:\d{2}(?=,)"
5:00

# Less than one day
$ uptime
12:47:30 up  4:24,  7 users,  load average: 0.34, 0.12, 0.07       
$ uptime | grep -Po "\d{1,2}:\d{2}(?=,)"
4:24     

或者sed -rn 's/.*([0-9]{1,2}:[0-9]{2}),.*/\1/p:

# More than one day
$ uptime
12:54:00 up 92 days,  5:07,  2 users,  load average: 0.03, 0.02, 0.05
$ uptime | sed -rn 's/.*([0-9]{1,2}:[0-9]{2}),.*/\1/p'
5:07

# Less than one day 
$ uptime
12:54:55 up  4:31,  7 users,  load average: 0.07, 0.10, 0.08
$ uptime | sed -rn 's/.*([0-9]{1,2}:[0-9]{2}),.*/\1/p'
4:31

更新:所以如果uptime 不到一个小时,输出是否又不同了!?

$ uptime
14:46:03 up 3 min,  4 users,  load average: 0.54, 0.75, 0.36

$ uptime
14:53:40 up 11 min,  4 users,  load average: 0.48, 0.62, 0.46

一个regexp 来统治他们:

$ sed -rn 's/.*up\s+(.*),\s+[0-9]+ users.*/\1/p' file
92 days,  5:00
4:24
11 min
3 min

我假设这也能处理好几年!

【讨论】:

  • +1 但不需要 gsub() 上的 ,$0 参数,因为这是默认设置。从其他人的回答看来, sub() 对于 uptime 输出可能就足够了。
  • 感谢@EdMorton 清晰与简洁。
  • +1 我认为这是正确的。我们应该相信 linux/unix 机器可以在不重启的情况下运行超过 1 天。 :)
  • @Kent 我想你误解了我说的最后一点所以我没有测试过少于一小时的正常运行时间。
  • @sudo_O 我没有误会。因为我没看到。我赞成,因为您的回答考虑了超过 1 天的正常运行时间,这将使 OP 的 awk 3 美元失败。从我的角度来看,OP 没有很好地定义这个问题,或者我(你也)想太多了。
【解决方案3】:

uptime | awk '{print $3}' | tr -d ,

【讨论】:

    【解决方案4】:

    鉴于@sudo_O 的正常运行时间输出示例(谢谢!):

    $ cat file
    12:46:18 up 92 days,  5:00,  2 users,  load average: 0.00, 0.01, 0.05
    12:47:30 up  4:24,  7 users,  load average: 0.34, 0.12, 0.07
    
    $ awk -F'[ ,]+' '{print $3 (/days/?" "$4" "$5:"")}' file
    92 days 5:00
    4:24
    
    $ sed 's/.*up *\(.*\), *[0-9]* users.*/\1/' file
    92 days,  5:00
    4:24
    

    【讨论】:

      【解决方案5】:

      使用sed:

      uptime | awk '{print $3}' | sed '$ s/,$//'
      

      【讨论】:

      • 您永远不必将awk 传递给sed
      • 但是为什么呢?我总是使用awk | sed
      • 因为awk可以做任何你想做sed做的事情
      • @mouviciel 您无需成为 awk 大师即可使用 awk '{...; sub(/,$/,"")} 而不是 awk '{...} | sed 's/,$/,""/',如果您将 awk 用于此类小事,那么您将很快学会。
      • @EdMorton 实际上awk $3“可能”是错误的。如果他的机器运行时间超过一天。
      猜你喜欢
      • 2017-12-01
      • 2018-11-25
      • 1970-01-01
      • 2011-07-01
      • 2022-11-22
      • 2016-08-17
      • 2019-10-04
      • 1970-01-01
      相关资源
      最近更新 更多