<
我有一个 RDF 文件,其中包含由和描绘的不同行数的数据块/>
。在每个块内,都有一个由 标识的字段name="some name"
。我需要根据 的值对块进行排序,name
而不更改每个块中任何行的顺序。此外,每个块中都有一个带有数字的字段。我需要对这些字段重新编号1到n基于每个块的排序位置。
这是 3 个块的示例:
<RDF:Description RDF:about="rdf:#$CHROME1"
NS1:name="AAA Carolinas"
NS1:urlToUse=""
NS1:whereLeetLB="off"
NS1:leetLevelLB="1"
NS1:hashAlgorithmLB="md5"
NS1:passwordLength="16"
NS1:usernameTB="user"
NS1:counter=""
NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV123456789"
NS1:prefix="6%Fl"
NS1:suffix="I$5g"
NS1:protocolCB="false"
NS1:subdomainCB="true"
NS1:domainCB="true"
NS1:pathCB="false"
/>
<RDF:Description RDF:about="rdf:#$CHROME2"
NS1:name="Adobe Forums"
NS1:urlToUse="adobeforums.com"
NS1:whereLeetLB="off"
NS1:leetLevelLB="1"
NS1:hashAlgorithmLB="md5"
NS1:passwordLength="12"
NS1:usernameTB="username"
NS1:counter=""
NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"
NS1:prefix=""
NS1:suffix=""
NS1:protocolCB="false"
NS1:subdomainCB="true"
NS1:domainCB="true"
NS1:pathCB="false"
NS1:pattern0="*adobeforums.com*"
NS1:patternenabled0="true"
NS1:patterndesc0=""
NS1:patterntype0="wildcard"
/>
<RDF:Description RDF:about="rdf:#$CHROME3"
NS1:name="Adorama"
NS1:urlToUse="adorama.com"
NS1:whereLeetLB="off"
NS1:leetLevelLB="1"
NS1:hashAlgorithmLB="md5"
NS1:passwordLength="8"
NS1:usernameTB="username"
NS1:counter=""
NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"
NS1:prefix=""
NS1:suffix=""
NS1:protocolCB="false"
NS1:subdomainCB="false"
NS1:domainCB="true"
NS1:pathCB="false"
NS1:pattern0="*adorama.com*"
NS1:patternenabled0="true"
NS1:patterndesc0=""
NS1:patterntype0="wildcard"
NS1:pattern1="www.adoramapix.com*"
NS1:patternenabled1="true"
NS1:patterndesc1=""
NS1:patterntype1="wildcard"
/>
我提到的数字就是$CHROME
上面例子中的数字。我是一位老汇编、COBOL、Fortran、Basic 程序员,但我不熟悉脚本或较新的语言。我可能可以在 Basic 程序中完成此操作,但如果可能的话,我想要一个 Linux 解决方案。
答案1
我希望有一些性格——或者至少有一些细绳- 永远不会出现在你的文件中。我假设这对于 来说是正确的|
。为了更安全,我会使用||
.
运行这个命令:
sed -n -e H -e '/^ *\/> *$/ { s/.*//; X; s/.*NS1:name="\([^"]*\)/\1&/; s/\n/||/gp }'你的文件| 排序| 荷兰-ba | sed -e 's/ *\([0-9]*\)[^|]*||\(.* RDF:about="rdf:#$CHROME\)[0-9]*/\2\ 1/' -e 's/||/\n/g'
注意:这(可能)需要您有 GNU sed。
概述
- 用于
sed
将文件转换为适合排序的格式(详情如下)。 - 对 的输出进行排序
sed
。 - 应用(添加)行号。使用任何能生成合适数字的命令。我喜欢
nl -ba
,但cat -n
也同样有效,而且可能还有其他选择。 - 用于
sed
从行开头去除行号并将其插入到后面CHROME
。将数据恢复为原始格式。
详细信息 - 第一个sed
命令
该sort
命令将每一行视为一条记录。因此,我们从输入文件中获取每个(分隔的)记录并将所有行连接起来,形成一长行。我们还将name
值复制到行的开头,以避免指定排序键。
使用该
-n
选项禁止自动打印。仅当我们说 时才会打印行p
。H
在每一行执行。这会将当前行附加到保留空间。从逻辑上讲,这可能更有意义复制将该<
行添加到保留空间(使用命令h
),然后附加所有后续行。我随意选择了这种方法。请注意,因为我们将
<
行附加到空的保留空间,所以聚合记录在开头有一个额外的换行符。查找包含 的行
/>
,可以选择在其前面和/或后面添加空格。当我们找到它时,我们就知道我们在保留空间中有完整的记录。仅在这些行上执行以下命令。s/.*//
清除图案空间(即擦除线条/>
)。这并不是真正丢弃任何信息;而是丢弃任何信息。该/>
行已经附加到保留空间(因为每一个行附加到保留空间)。x
交换模式空间和保持空间。这会将聚合(附加/串联)记录从保留空间检索到模式空间中。由于前面的 (s/.*//
) 命令,这会清除保留空间。s/.*NS1:name="\([^"]*\)/\1&/
查找名称字段并将其值复制到记录的开头。如果您可以使用带引号字符的名称,则此操作将会失败在里面。s/\n/||/gp
将模式空间中的每个换行符替换为||
. (这是将记录转换为一行的步骤。)由于p
,这将打印记录。
sed
当对示例文件运行时,第一个命令的输出是
AAA Carolinas||<RDF:Description RDF:about="rdf:#$CHROME1"|| NS1:name="AAA Carolinas"|| NS1:urlToUse=""|| NS1:whereLeetLB="off"|| NS1:leetLevelLB="1"|| NS1:hashAlgorithmLB="md5"|| NS1:passwordLength="16"|| NS1:usernameTB="user"|| NS1:counter=""|| NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV123456789"|| NS1:prefix="6%Fl"|| NS1:suffix="I$5g"|| NS1:protocolCB="false"|| NS1:subdomainCB="true"|| NS1:domainCB="true"|| NS1:pathCB="false"|| />
Adobe Forums||<RDF:Description RDF:about="rdf:#$CHROME2"|| NS1:name="Adobe Forums"|| NS1:urlToUse="adobeforums.com"|| NS1:whereLeetLB="off"|| NS1:leetLevelLB="1"|| NS1:hashAlgorithmLB="md5"|| NS1:passwordLength="12"|| NS1:usernameTB="username"|| NS1:counter=""|| NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"|| NS1:prefix=""|| NS1:suffix=""|| NS1:protocolCB="false"|| NS1:subdomainCB="true"|| NS1:domainCB="true"|| NS1:pathCB="false"|| NS1:pattern0="*adobeforums.com*"|| NS1:patternenabled0="true"|| NS1:patterndesc0=""|| NS1:patterntype0="wildcard"|| />
Adorama||<RDF:Description RDF:about="rdf:#$CHROME3"|| NS1:name="Adorama"|| NS1:urlToUse="adorama.com"|| NS1:whereLeetLB="off"|| NS1:leetLevelLB="1"|| NS1:hashAlgorithmLB="md5"|| NS1:passwordLength="8"|| NS1:usernameTB="username"|| NS1:counter=""|| NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"|| NS1:prefix=""|| NS1:suffix=""|| NS1:protocolCB="false"|| NS1:subdomainCB="false"|| NS1:domainCB="true"|| NS1:pathCB="false"|| NS1:pattern0="*adorama.com*"|| NS1:patternenabled0="true"|| NS1:patterndesc0=""|| NS1:patterntype0="wildcard"|| NS1:pattern1="www.adoramapix.com*"|| NS1:patternenabled1="true"|| NS1:patterndesc1=""|| NS1:patterntype1="wildcard"|| />
详细信息 - 第二个sed
命令
s/ *\([0-9]*\)[^|]*||\(.* RDF:about="rdf:#$CHROME\)[0-9]*/\2\1/
将线分成几部分:- 零个或多个空格。
- 行号(零个或多个数字)。这就成为了
\1
团体。 - 行号、值
name
及其||
后面的制表符。 - 不过记录上升了
RDF:about="rdf:#$CHROME
。这就成为了\2
团体。 - 旧记录编号(零个或多个数字)。
- 隐含地,记录的其余部分。
RDF:about="rdf:#$CHROME
然后它用和行号(新记录号)替换前五个部分。由于记录的其余部分不匹配,因此它不受该命令的影响。s/||/\n/g
用换行符替换每个||
行,恢复(重新创建)文件的原始多行结构。
明显地, …
…要将输出发送到文件,请在命令最后一行的最末尾添加(即在第二行的末尾)。然后您可以移动 ( ) > your_output_file
sed
mv
your_output_file
到你的原始文件。为命令指定--output=
(或 -o
) 选项是没有任何意义的sort
;的输出sort
必须进入应用行号的命令。如果您想捕获中间文件,请这么说。