3

我有一些块的文件,如下所示:

<start> test var=3333
<g>test=000000000000 tst <s>
<end>
...
<start> var=564735628
<title>somethink<\title>
<end>
...

而且我需要在循环中的和部分之间获得块。然后我需要在当前块中获取一些符号。我尝试这样做:

for block in $(cat $file | sed -n '/<start>/,/<end>/p;'); do
         echo $block 
done

结果是:

<start>

反而

<start> test 1
<g>test=000000000000 tst <s>
<end>

如何获取整个块以进行进一步处理?


好的,我试着解释一下 Source 是

<start> test var=3333
<g>test=000000000000 tst <s>
<end>

您的代码结果不是块。这只是一个刺痛。该字符串是<end>t> test var=3333tst <s> 如您所见,它是块的字符串彼此重叠。

4

5 回答 5

1

一种建议,这里不要使用sed。使用类似perlorpython的语言提供解析模块HTMLXML.

于 2012-10-02T12:12:00.317 回答
1

您可以执行以下操作:

block=""
cat $file | sed -n '/<start>/,/<end>/p;' | while read -r line; do
     if [ -z "$block" ]; then
         block="$line"
     else
         block=$(printf "%s\\n%s" "$block" "$line")
     fi

     if printf "%s\\n" "$line" | grep "<end>" > /dev/null; then
         echo "$block"
         block=""
     fi
done

正如choroba在他的回答中所说,您的 for 循环将使用 IFS 变量将 sed 的输出拆分为单独的字段,而 block 变量将仅包含一个字段。(即,块将包含<start>, then test, thenvar=3333等)。

一种解决方案是通过将 sed 的输出通过管道传输到循环命令中来强制它逐行读取,并使用该read命令读取该行。read 命令的-r标志强制它不将反斜杠解释为转义字符。现在我们的行有一个变量$line,但块没有。要获取该块,只需将这些行连接在一起,直到我们找到<end>字符串。

如果$block变量为空,我们可以简单地将 赋值$line给它。否则,我们使用该printf命令生成一个新字符串,其中包含$block与换行符连接的先前值和$line. 此换行符可防止该块变成单行。

为了测试我们是否找到了最后一行,我们可以打印块的当前值并查看 grep 是否找到它。我使用 printf 是因为当我们要打印的字符串以变量开头时,它比 echo 更安全(我们不能保证变量不以连字符开头, echo 可以解释为一个选项)。当我们真正找到一个块时,我们还必须记住清除块变量,以便为下一个块做好准备。

于 2012-10-02T12:13:50.613 回答
0

分词应用于sed命令的输出。您可以将 IFS 设置为空值以防止在sed输出上分词,但它会使整个输出sed变成一个“块”。我宁愿切换到像 Perl 这样更强大的语言。

于 2012-10-02T09:28:22.010 回答
0

通过更改 IFS 并在块之间插入分隔符,您可以遍历每个块。

例如,:用作分隔符

OLDIFS=$IFS; IFS=':'
blocks=$(sed -n '/start/,/end/ {/start/ s/^/:/; p}' file)
for block in ${blocks#:}; do
  echo "This is block $((count++))"
  echo "$block"
done
IFS=$OLDIFS

笔记:

  1. :通过在之前插入<start>并设置IFS为来“分隔”块:
  2. ${blocks#:}删除第一个:,否则:block1:block2...解释为emptyblock:block1:block2...,即循环遍历不存在的第一个块(它是空的,并且由于:放置方式而存在)
  3. 或者,:可以放在后面,<end>但是块的最后一行会变成<end>:\n这样,所以在下一个块的开始之前会有一个额外的换行符。
于 2012-11-03T18:43:49.640 回答
0

这可能对您有用(GNU sed 和 bash):

OIFS=$IFS; IFS=$'\n'; block=($(sed '/<start>/,/<end>/!d' file)); IFS=$OIFS
for x in "${!block[@]}"; do echo "${block[x]}"; done

将 sed 命令输出插入一个数组block并循环遍历该数组。

于 2012-10-02T15:56:13.777 回答