- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是 Linux/Bash 的新手,我正在学习以下指南作为我自己的教程:
虽然我不只是手动执行此操作,但我还尝试编写一个 bash 脚本来执行该指南中的所有步骤。
我坚持执行以下步骤:指南让您安装 nginx,然后从 nginx.conf 文件中删除以下文本 block :
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}enter code here
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
我试图使用 sed 来完成这个,使用如下命令:
sed -i '/server {/,/ location = /50x.html { } }/d' /etc/nginx/nginx.conf
但我无法让它成功匹配 block 的结尾(我无法弄清楚的正则表达式/特殊字符/空白错误,例如“sed:-e 表达式#1,字符 10:未终止地址正则表达式”)。我尝试转义特殊字符,但仍然卡住了。
我放弃了,而是选择在 block 开头的匹配项之后删除固定数量的行:
sudo sed -i '/server {/,+19d' /etc/nginx/nginx.conf
这有效,但也删除了另一个以 '/server{/' 开头的 block ,在文件其他地方注释掉了我不想要的文本。我进行了搜索,但无法找到仅在与此命令的第一次匹配后删除的方法。我看到了以下建议:
sudo sed -i '0,/server {/,+19d' /etc/nginx/nginx.conf
但是这些返回了错误:sed: -e expression #1, char 13: unknown command: `,'
总而言之,我的问题是:
如何使用 sed 删除嵌套的括号 block ?如果不可能,那么更好的工具是什么?我如何只在第一次匹配的情况下进行删除?
非常感谢您的阅读和任何帮助。
最佳答案
任何时候当你遇到涉及嵌套结构(圆括号、大括号等)的问题时,你可以立即知道这个问题对于sed
来说太难了,或者任何仅适用于正则表达式的工具。这是计算理论的结果,对此有一个不错的背景解释 Wikipedia page : 基本上,正则表达式仅实现有限状态自动机,但您需要具有下推自动机计算能力的东西。
另一种表达方式是“正则表达式不能计数”:在通用正则表达式执行器中,任意数量的左括号“(((”(它们之间可能有任意数量的非括号字符)结束通过一个右括号“)”。你可以编写(非常复杂的)正则表达式来处理三括号组与双括号组不同的方式,并且两者都与单括号组不同,但是有人出现并写了“( ((("在你面前炸毁了你的复杂方案。所以你写了一个指数更复杂的方法来处理带有四个括号的组,然后有人给了你五个......:-)
无论如何,结果是您需要一种更强大的语言。这些确实存在,您可以在 bash 脚本中编写自己的脚本(因为 bash 实现了算术),但是对于这些没有标准的开箱即用的答案。大多数人使用他们认为方便的任何语言编写小型解析器——或者您可以使用 Python 和 ply
包,或者使用 C 或 C++ 的 bison 或 yacc(包含在 Linux 中),尽管这些实际上是成熟的工具用于编写编译器的解析部分。
您还可以使用 awk 编写完整的解析器,使用 awk 的正则表达式来实现分词器。我已经为玩具示例这样做了,但不推荐这样做:一旦您学习了如何使用 lex 和 yacc(或 Python 中的 ply),您可能会发现使用它们实际上更容易。由于它们功能齐全,您可以使用它们编写真正的工具。
我建议在这里使用 ply,因为 Python 以一种易于使用的方式提供了所有复杂的存储管理位。请注意,词法分析和解析是一个相当大的话题,然后进入编译器,这是一个更大的话题。标记化和解析的概念并不难,只是一系列令人难以置信的数学支持不同的方法,以及多么上下文无关的语法意味着和暗示(按照维基百科链接)。
编辑:这是一个完整的实现,仅使用 ply 的扫描器部分。它有点长,但它展示了如何使用 ply 构建词法分析器,然后以一种相当俗气的方式使用它。
我不知道我对字符串和其他标记的处理是否正确,因为关于 nginx 输入文件格式的文档相当薄,但是由于标记是由正则表达式定义的,如果需要的话应该很容易调整.我也不是说它是实现 nginx 输入文件解析器的特别好的方法:如果你真的想读取和解释文件,而不是粗暴地破解它,你会可能想要至少有一点不同的东西,也许包括正确的语法。
#! /usr/bin/env python
from __future__ import print_function
import argparse
import collections
import sys
import ply.lex
t_COMMENT = r'\#.*'
t_BACKSLASHED = r'\\([\\{}])'
t_WORD = '[A-Za-z0-9_]+'
t_STRING = '("[^"]*")|' "('[^']*)'"
t_LB = '{'
t_RB = '}'
t_WHITE = '[ \t]+'
t_REST = '.'
tokens = [
'COMMENT',
'BACKSLASHED',
'WORD',
'STRING',
'LB',
'RB',
'WHITE',
'REST',
'NEWLINE',
]
def t_NEWLINE(t):
r'\n+'
t.lexer.lineno += len(t.value)
return t
# This never happens because '.' matches anything but newline and
# we have a newline rule; but if we don't define it, ply complains.
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
# Build the lexer
LEXER = ply.lex.lex()
def fill(tlist, howmany):
"build up token list - returns False if the list is all non-tokens"
while len(tlist) < howmany:
tlist.append(LEXER.token())
return tlist[0] is not None
def nth_is(tlist, offset, tok_type, tok_value=None):
"a sleazy kind of parser lookahead"
fill(tlist, offset + 1)
tok = tlist[offset]
if tok is None:
return False
if tok.type != tok_type:
return False
if tok_value is not None and tok.value != tok_value:
return False
return True
TEST_DATA = '''\
# a comment - gets copied
server {
stuff;
more { } stuff;
this is not a brace \{ because it is backslashed;
"and these strings }";
'do not close the server } either';
}
this gets copied;
'''
def main():
"main"
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--test', action='store_true')
parser.add_argument('inputfile', nargs='?', type=argparse.FileType('r'),
default=sys.stdin)
args = parser.parse_args()
if args.test:
LEXER.input(TEST_DATA)
else:
LEXER.input(args.inputfile.read())
# Tokenize; copy lines through except when dealing
# with the first "server" definition
looking_for_server = True
copying = True
eat_white_space_and_newline = False
brace_depth = 0
tlist = collections.deque()
while fill(tlist, 1):
if tlist[0].type == 'LB':
brace_depth += 1
elif tlist[0].type == 'RB':
if brace_depth > 0:
brace_depth -= 1
# If we went from 1 to 0 and are in
# non-copy mode, resume copying, but eat
# one white-space-and-newline
if brace_depth == 0 and not copying:
copying = True
eat_white_space_and_newline = True
tlist.popleft() # eat the }
continue
if looking_for_server:
check = 0
if tlist[0].type == 'WHITE':
fill(tlist, 2)
check = 1
else:
check = 0
if nth_is(tlist, check, 'WORD', 'server'):
# server followed by spaces and {, or by { => stop copying
if nth_is(tlist, check + 1, 'LB') or (
nth_is(tlist, check + 1, 'WHITE') and
nth_is(tlist, check + 2, 'LB')):
copying = False
looking_for_server = False
if check > 0:
tlist.popleft() # toss white space at 0 now
# We'll increment brace-depth when we actually consume
# the brace.
if copying:
if not eat_white_space_and_newline or \
tlist[0].type not in ('NEWLINE', 'WHITE'):
print(tlist[0].value, end='')
if tlist[0].type == 'NEWLINE':
eat_white_space_and_newline = False
tlist.popleft()
if __name__ == '__main__':
try:
sys.exit(main())
except KeyboardInterrupt:
sys.exit('\nInterrupted')
关于linux - 在 Bash 中用嵌套括号替换第一个文本实例的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48028973/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
Linux 管道可以缓冲多少数据?这是可配置的吗? 如果管道的两端在同一个进程中,但线程不同,这会有什么不同吗? 请注意:这个“同一个进程,两个线程”的问题是理论上的边栏,真正的问题是关于缓冲的。 最
我找到了here [最后一页] 一种有趣的通过 Linux 启动 Linux 的方法。不幸的是,它只是被提及,我在网上找不到任何有用的链接。那么有人听说过一种避免引导加载程序而使用 Linux 的方法
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我试图了解 ld-linux.so 如何在 Linux 上解析对版本化符号的引用。我有以下文件: 测试.c: void f(); int main() { f(); } a.c 和 b.c:
与 RetroPie 的工作原理类似,我可以使用 Linux 应用程序作为我的桌面环境吗?我实际上并不需要像实际桌面和安装应用程序这样的东西。我只需要一种干净简单的方法来在 RaspberryPi 上
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
有什么方法可以覆盖现有的源代码,我应该用 PyQt、PyGTK、Java 等从头开始构建吗? 最佳答案 如果您指的是软件本身而不是它所连接的存储库,那么自定义应用程序的方法就是 fork 项目。据我所
我的情况是:我在一个磁盘上安装了两个 linux。我将第一个安装在/dev/sda1 中,然后在/dev/sda2 中安装第二个然后我运行第一个系统,我写了一个脚本来在第一个系统运行时更新它。
我在 i2c-0 总线上使用地址为 0x3f 的系统监视器设备。该设备在设备树中配置有 pmbus 驱动程序。 问题是,加载 linux 内核时,这个“Sysmon”设备没有供电。因此,当我在总线 0
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我正试图在 linux 模块中分配一大块内存,而 kalloc 做不到。 我知道唯一的方法是使用 alloc_bootmem(unsigned long size) 但我只能从 linux 内核而不是
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我有 .sh 文件来运行应用程序。在该文件中,我想动态设置服务器名称,而不是每次都配置。 我尝试了以下方法,它在 CentOS 中运行良好。 nohup /voip/java/jdk1.8.0_71/
我是在 Linux 上开发嵌入式 C++ 程序的新手。我有我的 Debian 操作系统,我在其中开发和编译了我的 C++ 项目(一个简单的控制台进程)。 我想将我的应用程序放到另一个 Debian 操
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我使用4.19.78版本的稳定内核,我想找到带有企鹅二进制数据的C数组。系统启动时显示。我需要在哪里搜索该内容? 我在 include/linux/linux_logo.h 文件中只找到了一些 Log
我知道可以使用 gdb 的服务器模式远程调试代码,我知道可以调试针对另一种架构交叉编译的代码,但是是否可以更进一步,从远程调试 Linux 应用程序OS X 使用 gdbserver? 最佳答案 当然
是否有任何可能的方法来运行在另一个 Linux 上编译的二进制文件?我知道当然最简单的是在另一台机器上重建它,但假设我们唯一能得到的是一个二进制文件,那么这可能与否? (我知道这可能并不容易,但我只是
我是一名优秀的程序员,十分优秀!