我试图替换看起来像这样的文本文件的一部分
[stuff before]
<!--WEIRD_SPECIAL_COMMENT_BEGIN-->
[stuff here, most to be removed but everything within $TEXT-WANT-TO-KEEP$ should be kept]
<!--WEIRD_SPECIAL_COMMENT_END-->
[stuff after]
但在WEIRD_SPECIAL_COMMENT_BEGIN和WEIRD_SPECIAL_COMMENT_END之间有一些我想保留的文字。文本始终用$符号括起来。
所以我真正想要的是将文字保存在$符号中,删除WEIRD_SPECIAL_COMMENT_BEGIN和WEIRD_SPECIAL_COMMENT_END之间的所有内容,并将文本粘贴到$ ... $中。 NEW_TEXT_1之前和NEW_TEXT_2。我想到的最终结果是这样的:
[stuff before]
<NEW_TEXT_1>
[TEXT_I_WANT_TO_KEEP]
<NEW_TEXT_2>
[stuff after]
我刚接触shell,但无法使用sed
命令弄清楚如何执行此操作。任何帮助非常感谢。
更新:
我的文件非常混乱,但一个简单的工作示例可能是乳胶文档
[stuff before]
\begin{enumerate}
\item bla bla
\item bla bla
\item $x = y$
\end{enumerate}
[stuff after]
结果我想到的可能是这样的
[stuff before]
\begin{equation}
x = y
\end{equation}
[stuff after]
答案 0 :(得分:0)
以下是我拍摄的照片:
cat stuff.txt | \
sed 's/<\!--.*BEGIN-->/<NEW_TEXT_1>/' | \
sed 's/<\!--.*END-->/<NEW_TEXT_2>/' | \
sed 's/^.*\($.*$\).*$/\1/'
编辑:尝试#2,使用bash脚本!
#!/bin/bash
IN=0
while read s; do
if [ "$s" = "\\begin{equation}" ]; then
IN=1
continue
fi
if [ "$IN" = "1" ]; then
if [ "$s" = "\\end{equation}" ]; then
IN=0
continue
else
echo $s | sed 's/.*\(\$.*\$\).*/\1/'
fi
else
echo $s
fi
done < stuff.txt;
edit2:尝试3;)这个bash脚本开始变得非常难看,但我想看看我是否可以使它工作,所以这里是:
#!/bin/bash
#backslashes and braces don't match well in bash string comparisons.
#so, lets replace them with better identifiers.
cat stuff2.txt | sed 's/\\\(begin\|end\){enumerate}/XXXX\1/' > tmpfile
IN=0
while read s; do
if [ "$s" = "XXXXbegin" ]; then
IN=1
continue
fi
if [ "$IN" = "1" ]; then
if [ "$s" = "XXXXend" ]; then
IN=0
continue
else
#sed -n means don't print anything
# but the /p at the end means print matches
echo $s | sed -n 's/.*\$\(.*\)\$.*/\1/p'
fi
else
echo $s
fi
done < tmpfile
rm -f tmpfile
答案 1 :(得分:0)
我无法想象能够使用简单的grep
或sed
执行此操作。这些是基于内衬的工具,因此。我可以想象一个循环遍历文件的简单脚本:
while read line
do
# Magic happens here
done < $myfile
现在,我们必须弄清楚魔法应该是什么......
更简单的是awk脚本可以做同样的事情:
awk '{ #Magic stuff happens here }' $myfile
awk脚本在隐含循环上运行。
让我们使用一个变量来跟踪你是否在那些奇怪的东西中:
awk '{
line = $0
if ( $0 = "<!--WEIRD_SPECIAL_COMMENT_BEGIN-->" ) {
weird_stuff = 1
}
if ( $0 = "<!--WEIRD_SPECIAL_COMMEND_END-->" ) {
weird_stuff = 0
}
if ( weird_stuff = 1 ) {
munge line...
}
print line
}' $myfile
现在,我们必须弄清楚如何消除这条线。 awk可以处理正则表达式,但它在处理这样的东西方面并不像Perl那么丰富。
你队中的$
可以包含多件事吗?如果是这样,我们可以使用index
命令查找$
awk '{
line = $0
if ( $0 = "<!--WEIRD_SPECIAL_COMMENT_BEGIN-->" ) {
weird_stuff = 1
}
if ( $0 = "<!--WEIRD_SPECIAL_COMMEND_END-->" ) {
weird_stuff = 0
}
if ( weird_stuff != 1 ) { # This is not in the weird stuff. Print the line
print $0
next
}
# Weird Stuff at this point forward
first_char = index( $0, "$")
if ( first_char = 0 ) {
next # Nothing to print
}
subline = substr( $0, first_char + 1 ) # Remove up to the $
second_char = index( subline, "$" )
if ( second_char = 0 ) {
next # No second "$" found. Nothing to print
}
print substr( subline, 1, $second_char - 1)
}' $myfile
我的awk
真的非常生疏。当Perl在版本3中发现Perl时,我已经停止使用awk
。所以,我不能保证这个程序是否有效。我甚至没有测试它。
但是,它确实可以让您了解如何处理您的问题。我本可以做一些类似的事情:
while read line
do
# Magic stuff happens here...
done < $myfile
如果我这样做,我本可以使用sed
,它可以一次性从输入字符串的其余部分中取出$...$
。
答案 2 :(得分:0)
等待。 Perl还好吗?我刚刚意识到它在你的标签中。你的头衔说“Shell Script”。对大多数人来说,这意味着awk
很好,但Perl不是。
#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);
use File::stat;
my $weird_flag = 0;
while ( my $line = <DATA> ) {
chomp $line;
if ( $line =~ /\\begin{enumerate}/ ) {
$weird_flag = 1;
say "$line";
next;
}
if ( $line =~ /\\end{enumerate}/ ) {
$weird_flag = 1;
say "$line";
next;
}
if ( not $weird_flag ) {
say "$line";
}
else {
if ( $line =~ s/.*?\$(.*)\$.*/$1/ ) {
say "$line";
}
}
}
__DATA__
[stuff before]
\begin{enumerate}
\item bla bla
\item bla bla
\item $x = y$
\end{enumerate}
[stuff after]
答案 3 :(得分:0)
这可能适合你(GNU sed):
sed -e '/<!--WEIRD_SPECIAL_COMMENT_BEGIN-->/,/<!--WEIRD_SPECIAL_COMMENT_END-->/{//d;s/[^$]*\$\([^$]*\).*/[\1]/;i\<NEW_TEXT_1>' -e 'a\<NEW_TEXT_2>' -e '}' file