【问题标题】:sed - pass match to external commandsed - 将匹配传递给外部命令
【发布时间】:2012-07-30 09:50:14
【问题描述】:

我使用 sed 编写了一个小脚本来转换它:

kaefert@Ultrablech ~ $ cat /sys/class/power_supply/BAT0/uevent
POWER_SUPPLY_NAME=BAT0
POWER_SUPPLY_STATUS=Full
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_TECHNOLOGY=Li-ion
POWER_SUPPLY_CYCLE_COUNT=0
POWER_SUPPLY_VOLTAGE_MIN_DESIGN=7400000
POWER_SUPPLY_VOLTAGE_NOW=8370000
POWER_SUPPLY_POWER_NOW=0
POWER_SUPPLY_ENERGY_FULL_DESIGN=45640000
POWER_SUPPLY_ENERGY_FULL=44541000
POWER_SUPPLY_ENERGY_NOW=44541000
POWER_SUPPLY_MODEL_NAME=UX32-65
POWER_SUPPLY_MANUFACTURER=ASUSTeK
POWER_SUPPLY_SERIAL_NUMBER= 

转换成这样的 csv 文件格式:

kaefert@Ultrablech ~ $ Documents/Asus\ Zenbook\ UX32VD/power_to_csv.sh 
"date";"status";"voltage µV";"power µW";"energy full µWh";"energy now µWh"
2012-07-30 11:29:01;"Full";8369000;0;44541000;44541000 
2012-07-30 11:29:02;"Full";8369000;0;44541000;44541000 
2012-07-30 11:29:04;"Full";8369000;0;44541000;44541000
... (in a loop)

我现在想要将这些数字中的每一个除以 1.000.000,这样它们就不会代表 µV,而是 V 和 W,而不是 µW,这样一目了然就可以轻松解释它们。当然,一旦我在 libre office calc 中打开了这个 csv,我之后可以手动执行此操作,但我想自动化它。

所以我发现,我可以在 sed 之间调用外部程序,如下所示:

...
s/\nPOWER_SUPPLY_PRESENT=1\nPOWER_SUPPLY_TECHNOLOGY=Li-ion\nPOWER_SUPPLY_CYCLE_COUNT=0\nPOWER_SUPPLY_VOLTAGE_MIN_DESIGN=7400000\nPOWER_SUPPLY_VOLTAGE_NOW=\([0-9]\{1,\}\)/";'`echo 0`'\1/

并且我可以通过这样的方式获得我想要的值:

echo "scale=6;3094030/1000000" | bc | sed 's/0\{1,\}$//'

但现在的问题是,我如何将匹配“\1”传递给外部命令?

如果您有兴趣查看完整的脚本,可以在此处找到: http://koega.no-ip.org/mediawiki/index.php/Battery_info_to_csv

【问题讨论】:

  • 我猜是这样:kaefert@Ultrablech ~ $ sed --version GNU sed 版本 4.2.1
  • 感谢信息,然后我将我的想法添加为答案。

标签: linux bash sed css


【解决方案1】:

如果您的 sed 是 GNU sed。您可以使用 'e' 将匹配的组传递给 sed 命令中的外部命令/工具。

一个例子可能有助于说明清楚:

说,你有问题:
你有一个字符串"120+20foobar",现在你想得到120+20部分的计算结果,并将“foobar”部分的“oo”替换为“xx”。

注意,这个例子不是为了解决上面的问题,只是为了 显示 sed 'e' 用法

所以你可以在第一个匹配组中创建120+20,在第二组中休息,然后将两组传递给不同的命令/工具,然后得到结果。喜欢:

   kent$  echo "100+20foobar"|sed -r 's#([0-9+]*)(.*)#echo  \1 \|bc\;echo \2 \| sed "s/oo/xx/g"#ge'
    120
    fxxbar

这样,您可以一个一个地嵌套多个 sed,直到迷路。 :D

【讨论】:

  • 这正是我想要的!我试图通过添加以下行来将其添加到我的脚本中:“s/([0-9]\{1,\})/echo \1/e” - 但只要我在在这一行的末尾,他尝试运行先前打印的东西,这些东西肯定与这一行不匹配作为命令.. --> "sh: 1: Full: not found"
  • 好的,解决了。 e 不是我最初认为的修饰符,而是它自己的命令,它使 sed 执行 linux 命令行上的所有结果文本。所以我必须调整一切,这样才能奏效。如果有人想看到结果,我已经在kaefert.is-a-geek.org/mediawiki/index.php/Battery_info_to_csv更新脚本
  • @Sławosz 有一个类似的问题,具有相同的技巧。我在那里解释。看看这个:stackoverflow.com/questions/15454914
  • 这里是用户@kaefert的存档链接:web.archive.org/web/20140414054655/https://…
【解决方案2】:

由于sed 自己不做算术,我建议使用awk 来处理类似的事情,例如将第 3、第 5 和第 6 个字段除以一百万,请执行以下操作:

 awk -F';' -v OFS=';' '
   NR == 1
   NR != 1 { 
     $3 /= 1e6
     $5 /= 1e6
     $6 /= 1e6
     print
   }'

说明

  • -F';'-v OFS=';' 指定输入和输出字段分隔符。
  • NR == 1 直接通过第一行。
  • NR != 1如果不是第一行,分割打印。

【讨论】:

  • 感谢您的回答。我没有这样做的原因是我想一步完成所有事情。使用这种方法,我将需要重写所有内容,或者首先执行我的 sed 工作并将 sed 的输出用作 awk 的输入,然后使用 awk 解析 csv。可能也可以,但是由于有另一种方法可以直接使用 sed 进行操作,所以我使用了那个方法。
【解决方案3】:

要直接除以 1,000,000,您可以这样做:

Q='3094030/1000000'
sed ':r /^[[:digit:]]\{7\}/{s$\([[:digit:]]*\)\([[:digit:]]\{6\}\)/1000000$\1.\2$;p;d};s:^:0:;br;d'

【讨论】:

  • 这是个好主意!但问题是这些数字也可能少于 6 位,在这种情况下,您的解决方案将不匹配它
  • 我想我会接受肯特的回答,我会在完成对我的脚本的改编后立即接受它;)
猜你喜欢
  • 2019-02-16
  • 2017-12-15
  • 2015-08-03
  • 2019-09-11
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-15
相关资源
最近更新 更多