如何解决sed 在下一行中复制子字符串
我有一个 .po 文件,如果 msgstr 为空,我需要将 msgid 值复制到 msgstr 值中。
例如
msgid "Hello"
msgstr ""
msgid "Dog"
msgstr "Cane"
应该变成
msgid "Hello"
msgstr "Hello"
msgid "Dog"
msgstr "Cane"
目前,出于测试目的,我正在处理另一个文件,但最终脚本将内联工作。
#!/bin/bash
rm it2.po
sed $'s/^msgid.*/&\\\n---&/' it.po > it2.po
sed -i '/^msgstr/d' it2.po
sed -i 's/^---msgid/msgstr/' it2.po
这个脚本有两个问题(至少):
任何帮助将不胜感激。提前致谢。
解决方法
您可以考虑使用更好的工具 gnu awk
而不是 sed
:
awk -i inplace -v FPAT='"[^"]*"|\\S+' '$id != "" && $1 == "msgstr" && (NF==1 || $2 == "\"\"") {$2=id} $1 == "msgid" {id=$2} 1' file
msgid "Hello"
msgstr "Hello"
msgid "Dog"
msgstr "Cane"
-v FPAT='"[^"]*"|\\S+'
使带引号的字符串或任何非空白字段成为单个字段。
更易读的形式:
awk -i inplace -v FPAT='"[^"]*"|\\S+' '
$id != "" && $1 == "msgstr" && (NF==1 || $2 == "\"\"") {$2=id}
$1 == "msgid" {id=$2}
1' file
,
使用 GNU awk
并仅显示示例,我们可以尝试以下操作。
awk -v RS='"[^"]*"|\n+' '
RT=="\n"{ next }
$0~/^msgstr/{
if(RT=="\"\""){ $0=$0 val }
else { $0=$0 RT }
}
$0~/^msgid/ { val=RT
$0=$0 RT }
RT
' Input_file
第二个解决方案: 与上面的解决方案略有不同,上面只需要出现 1 或 2 次 "
但这会一直工作到新的一行来自一行中第一次出现 "
之后会有所帮助,再次使用所示示例进行编写和测试。
awk -v RS='"[^\n]*|\n+' '
RT=="\n"{ next }
$0~/^msgstr/{
if(RT=="\"\""){ $0=$0 val }
else { $0=$0 RT }
}
$0~/^msgid/ { val=RT
$0=$0 RT }
RT
' Input_file
说明:为以上添加详细说明。
awk -v RS='"[^"]*"|\n+' ' ##Starting awk program from here and setting record separator as " till " comes or new lines.
RT=="\n"{ next } ##If RT is newline then take cursor to next line.
$0~/^msgstr/{ ##Checking if line starts from msgstr then:
if(RT=="\"\""){ $0=$0 val } ##Checking if RT us "" then add val to current line.
else { $0=$0 RT } ##Else simply add RT.
}
$0~/^msgid/ { val=RT ##Checking if line starts from msgid then make val to RT
$0=$0 RT } ##Adding RT to $0.
RT ##Printing line if RT is not null.
' Input_file ##Mentioning Input_file name here.
,
这可能对你有用(GNU sed):
sed -E 'N;s/(msgid "(.*)".*msgstr )""/\1"\2"/;P;D' file
打开一个两行窗口,如果第一行包含 msgid
,第二行包含 msgstr ""
,则将 msgstr
值替换为 msgid
值。打印/删除第一行并重复。
由于输入文件的结构如此简单且一致,我认为以下内容应该足够了(它适用于您提供的 3 个示例):
sed -zE 's/(msgid "([^"]+)"\nmsgstr ")"/\1\2"/g' your_file
-
-z
使文件成为带有嵌入\n
的长输入字符串,因此我们不需要N
、D
或其他命令,因为整个文件已经在模式空间中; -
-E
让我们使用(
、)
和+
代替\(
、\)
和\+
(以及其他类似的东西) - 最外层的
()
捕获msgid "Hello"\nmsgstr "
(关闭的"
匹配但未捕获); - 最里面的
()
捕获第一个双引号字符串; -
\1\2"
连接匹配的文本(最后的"
除外,正如我上面提到的),文本位于前两个"
之间,以及结束"
, - 标志
g
将在整个文件中应用替换。
如果前导字符串不是那么重要(例如它们总是相同的,并且行总是显示为 msgid
后跟 msgstr
),您可以将上面的命令压缩更多:
sed -zE 's/(([^"]+)"\n[^\n]*")"/\1\2"/g' your_file
,
您可以使用保留空间:
sed '
/^msgid[\t ]*/ {
p
s///
x
d
}
/^msgstr[\t ]*""/ {
x
s/^/msgstr /
}
' <in.po >out.po
- 如果行以
msgid
开头- 打印
- 删除关键字
- 保存字符串以保持
- 转到下一行
- else 如果行以
msgstr
开头且值为空- 从保留中检索字符串
- 添加关键字
- 隐式打印
这是一个简单的 sed
脚本,它将最新的 msgid
保留在保留空间 (h
) 中,然后将其带回来 (x
) 并将其更改为 {{1 }} 如果它看到一个空的 msgstr
。
msgstr
另请注意,您通常如何将多个 sed -e '/^msgid "/h' -e '/^msgstr ""/!b' \
-e x -e 's/^msgid/msgstr/' it.po >it2.po
语句与 sed
组合在一起,而不是创建一个新文件,然后对其重复运行 -e
。 sed -i
是一种脚本语言;想用就学。
(某些 sed
变体不能容忍这种安排;如果您对此有困难,可以将脚本组合成一个字符串,并在语句之间使用分号。)
话虽如此,sed
在很大程度上是一种只写语言。也许使用简单的 Awk(或 Python 或其他)解决方案会更好。
sed
,
保持简单并使用awk,例如在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ awk '$2~/""/{$2=p} {p=$2} 1' it.po
msgid "Hello"
msgstr "Hello"
msgid "Dog"
msgstr "Cane"
如果这不是您所需要的全部,那么编辑您的问题以提供更全面的示例输入/输出,包括不适用的情况。
既然你有 -i
的 GNU sed,如果你想“就地”编辑,你也有或可以安装 -i inplace
的 GNU awk,或者像其他任何人一样做 tmp=$(mktemp) && awk 'script' file > "$tmp" && mv "$tmp" file
命令。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。