bash:在长命令结束时解析数字

时间:2017-05-17 22:00:42

标签: bash

我正在编写一个shell脚本,它将运行一个命令并解析出最后几个数字(每次更改)。

运行npm run server后要解析的文本,输出:

Please visit http;//mysite.com/id/2318

我想解析该值并将其分配给id

2318

我的尝试:

id=$(echo npm run server | sed -n 's:.*id\/\(.*\)\n.*:\1:p')

没有任何东西被退回。

2 个答案:

答案 0 :(得分:2)

解决原始单行:

  

我的尝试:

id=$(echo npm run server | sed -n 's:.*id\/\(.*\)\n.*:\1:p') 
     

没有   正在退货。

您可以尝试这样做:

id=$(npm run server | sed -E -e 's:(^.*)(id/)(.*$):\3:g')

注意:这解决了原始尝试的组件 显然 存在一些可行性问题。这并没有考虑任何因素,除了你应该从运行命令得到的引用输出字符串的前提。的即。我使用以下命令重现了这个:

echo 'Please visit http;//mysite.com/id/2318' | sed -E -e 's:(^.*)(id/)(.*$):\3:g'

因此,假设当您运行npm run server时,您会得到输出'Please visit http;//mysite.com/id/2318'(顺便说一下 - 我建议可能是http //而不是http ; //),那么这个命令应该只返回id组件。

请注意,如果它是stderr:

如果您尝试过滤的文本是从stderr而不是stdout出来的,那么您实际上可能需要使用它:

id=$(npm run server  &> >(sed -E -e 's:(^.*)(id/)(.*$):\3:g'))

例如,解析未配置的npm服务器的输出:

06:38:23 ✗ :~ >npm run server
npm ERR! Darwin 15.5.0

06:38:23 ✗ :~ >npm run server | sed -E -e "s/(Darwin)/HELLO/g" npm ERR! Darwin 15.5.0

06:38:56 ✗ :~ >npm run server &> >(sed -E -e "s/(Darwin)/HELLO/g") npm ERR! HELLO 15.5.0

您可以在bash手册中看到有关重定向stderr的信息:

Redirecting Standard Output and Standard Error
   Bash  allows both the standard output (file descriptor 1) and the stan-    dard error output (file descriptor 2) to  be  redirected  to  the  file    whose name is the expansion of word with this construct.      There  are  two  formats  for  redirecting standard output and standard    error:             &>word    and           >&word      Of the two forms, the first is preferred.

答案 1 :(得分:1)

我假设:

  • 您要将npm run server作为命令调用。
  • 此命令在某个时刻在其标准输出上发出给定的消息(与stderr相反,直接发送到TTY等)。
  • 此命令自我背景,并且即使在给出输出后也希望它继续运行。
  • npm run server在启动它的shell脚本退出后继续运行并不重要。

如果所有这些假设都是正确的,请考虑为此工作替换流程:

#!/usr/bin/env bash
regex='Please visit .*/([[:digit:]]+)$'    # define a regex to search for the string
exec 3< <(npm run server)                  # attach output from "npm run server" to FD 3

## the action is here: searching through output from server until we find a match
while read -r server_output <&3; do        # loop reading a line at a time from the server
  if [[ $server_output =~ $regex ]]; then  # if a line matches the regex...
    id=${BASH_REMATCH[1]}                  # then put the first capture group in a variable
    break                                  # and stop looping further.
  fi
done

## after-the-fact: log success/failure, and set up any future output to be consumed
## ...so the server doesn't hang trying to write later output/logs to stdout w/ no readers.
if [[ $id ]]; then                         # if that variable contains a non-empty value
  echo "Detected server instance $id" >&2  # log it...
  cat </dev/fd/3 >/dev/fd/2 & cat_fd=$!    # start a background process to copy any further
                                           # stdout from service to stderr...
  exec 3<&-                                # then close our own copy of the handle.
else
  echo "Unable to find an id in stdout of 'npm run server'" >&2
  exit 1
fi

## and we're done: if you like, run your other code here.

## also: if you want to wait until the server has exited
##       (or at least closed its stdout), consider:
[[ $cat_fd ]] && wait "$cat_fd"