在模式前提取数字
Extracting a number before a pattern
我有一个包含这样一个序列的文件(如果您想知道的话,这是一个用于国际象棋符号的 PGN 文件):
1. e4 e5 2. Nf3 Nf6 3. Nc3 d6 4. d4 a6 5. Bc4 Be6 6. Bxe6 fxe6 7. Be3 Nc6 8. a3 h6 9. Qd3 Qd7 10. b4 b6 11. d5 exd5 12. Nxd5 Ne7 13. c4 Nexd5 14. exd5 e4 15. Qe2 exf3 16. Qxf3 O-O-O 17. O-O Re8 18. h3 Kb8 19. a4 Be7 20. b5 a5 21. Bd4 Ref8 22. Rfe1 Ne8 23. Qe3 Rf7 24. Qe6 Bd8 25. Re3 Re7 26.
Qxd7 Rxd7 27. Rae1 Nf6 28. g4 g5 29. Re6 Rf7 30. Kg2 h5 31. f3
注意它被分成几行。现在,从这个不断更新的文件中,我想提取最后一个点之前的数字,在本例中为 31
.
我设法只提取了最后一行并删除了可能的空白行:
sed '/^ *$/d' thefile.pgn | tail -1
但是,我不知道如何捕获点之前的最后一个数字。有没有可以完成这项工作的工具(awk、sed、grep、whathaveyou)?
如果文件只有一行,可以使用sed
:
$ sed -r 's/.* ([0-9]+)\. \w+$//' file
31
这匹配所有行并捕获行尾之前的最后一个数字块。然后,它用 </code>.</p> 打印回来
<p>如果文件包含很多行,让我们去 <code>grep
:
grep -Po " \K[0-9]+(?=\.)" file
有了这个,你可以在不同的行中得到所有的数字。要获取最后一行,只需通过管道输入 tail -1
:
$ grep -Po " \K[0-9]+(?=\.)" file | tail -1
31
它的工作原理是匹配出现在一个点之前的所有数字。当我们使用 -o
时,每个匹配项都打印在不同的行中,因此使用 tail -1
来获取最后一个匹配项。
您的 sed
脚本也可以轻松扩展以执行 tail
和 grep
部分。 (使用 sed -n
和正则表达式来控制打印,甚至不再需要删除空行。)
sed -n '$s/^.* \([1-9][0-9]*\)\.[^.]*$//p' thefile.pgn
这是假设最后一行永远不会为空。适应这个额外的要求也不难。这是一个稍微复杂一点的版本:
sed -n '/^.* \([1-9][0-9]*\)\.[^.]*$/{;s///;x;};$!b;x;p' thefile.pgn
与模式匹配的行将减少到最后一个数字并存储。在最后一行,检索存储的字符串并打印它。
这个 awk 也可以工作:
awk -F '\.' 'END{split($(NF-1), a, " "); print a[length(a)]}' file
31
谢谢大家!很难在答案之间做出选择。这是我的版本:
sed -e 's/\*//' -e '/^ *$/d' thefile.p | tail -1 | awk '{print $(NF-1)}' FS='[ .]+'
我接受 fedorqui 的回答,因为它更优雅。
我有一个包含这样一个序列的文件(如果您想知道的话,这是一个用于国际象棋符号的 PGN 文件):
1. e4 e5 2. Nf3 Nf6 3. Nc3 d6 4. d4 a6 5. Bc4 Be6 6. Bxe6 fxe6 7. Be3 Nc6 8. a3 h6 9. Qd3 Qd7 10. b4 b6 11. d5 exd5 12. Nxd5 Ne7 13. c4 Nexd5 14. exd5 e4 15. Qe2 exf3 16. Qxf3 O-O-O 17. O-O Re8 18. h3 Kb8 19. a4 Be7 20. b5 a5 21. Bd4 Ref8 22. Rfe1 Ne8 23. Qe3 Rf7 24. Qe6 Bd8 25. Re3 Re7 26.
Qxd7 Rxd7 27. Rae1 Nf6 28. g4 g5 29. Re6 Rf7 30. Kg2 h5 31. f3
注意它被分成几行。现在,从这个不断更新的文件中,我想提取最后一个点之前的数字,在本例中为 31
.
我设法只提取了最后一行并删除了可能的空白行:
sed '/^ *$/d' thefile.pgn | tail -1
但是,我不知道如何捕获点之前的最后一个数字。有没有可以完成这项工作的工具(awk、sed、grep、whathaveyou)?
如果文件只有一行,可以使用sed
:
$ sed -r 's/.* ([0-9]+)\. \w+$//' file
31
这匹配所有行并捕获行尾之前的最后一个数字块。然后,它用 </code>.</p> 打印回来
<p>如果文件包含很多行,让我们去 <code>grep
:
grep -Po " \K[0-9]+(?=\.)" file
有了这个,你可以在不同的行中得到所有的数字。要获取最后一行,只需通过管道输入 tail -1
:
$ grep -Po " \K[0-9]+(?=\.)" file | tail -1
31
它的工作原理是匹配出现在一个点之前的所有数字。当我们使用 -o
时,每个匹配项都打印在不同的行中,因此使用 tail -1
来获取最后一个匹配项。
您的 sed
脚本也可以轻松扩展以执行 tail
和 grep
部分。 (使用 sed -n
和正则表达式来控制打印,甚至不再需要删除空行。)
sed -n '$s/^.* \([1-9][0-9]*\)\.[^.]*$//p' thefile.pgn
这是假设最后一行永远不会为空。适应这个额外的要求也不难。这是一个稍微复杂一点的版本:
sed -n '/^.* \([1-9][0-9]*\)\.[^.]*$/{;s///;x;};$!b;x;p' thefile.pgn
与模式匹配的行将减少到最后一个数字并存储。在最后一行,检索存储的字符串并打印它。
这个 awk 也可以工作:
awk -F '\.' 'END{split($(NF-1), a, " "); print a[length(a)]}' file
31
谢谢大家!很难在答案之间做出选择。这是我的版本:
sed -e 's/\*//' -e '/^ *$/d' thefile.p | tail -1 | awk '{print $(NF-1)}' FS='[ .]+'
我接受 fedorqui 的回答,因为它更优雅。