Board logo

标题: stream editor (sed) for dos, win32,*nix [打印本页]

作者: twf_cc     时间: 2004-8-2 00:00    标题: stream editor (sed) for dos, win32,*nix

http://www.student.northpark.edu/pemente/sed/



sed , very power  stream editor for filtering text....input...etc



GNU sed 4.07 now ported to MSDOS  

example for using sed under WinXP cmd.exe



@echo off

date /t

ipconfig | findstr  /C:"IP Address" > NUL

if errorlevel 1 (

echo 127.0.0.1

) else (

ipconfig | sed "s/IP Address/!d;s/.*: //"

)



example to make a if -else statment



/^[^A-Za-z \t\n]*[0-9]*[^a-zA-Z \t\n]*[0-9]*[^A-Za-z \t\n]*$/ {

s/.*/&: \tNumber/

t end

}

/^[^0-9 \t\n]*[A-Za-z]*[^0-9 \t\n]*[A-Za-z]*[^0-9 \t\n]*$/ {

s/.*/&: \tLetter/

t end

}

/^[^ \t\n]*[0-9A-Za-z]*[^ \t\n]*[0-9A-Za-z]*[^ \t\n]*$/ {

s/.*/&: \tNumber and letter/

t end

}

/^[ \

]*$/ {

s/./A blank line/

t end

}



:end



under cygwin bash prompt :

~$ echo "123" | sed -f if-else.sed

123: Number

~$ echo "wer" | sed -f if-else.sed

wer: Letter



you may check the wed site to find out more information with sed



It is a free software,




作者: Climbing     时间: 2004-8-2 00:00
看得我头好大。
作者: twf_cc     时间: 2004-8-2 00:00
regluar expression  ==> sed , awk ,perl ,python ,tcl/tk, egrep, grep, ruby.... etc
很多program 都用上,學它非常有用
winxp 的 findstr 用的也是 regexp
findstr /? 可看到它的簡單介紹

sed 處理文本非常好用

假如我有一文件如是,
This is a first line.

this is second.


this is third.



this is forth.






this is fivth.

我得把空行只剩一行在每行子之間,在第一行前加一空行,
可寫一個 sed 腳本,如此

/^.\{1,\}/ {
i\
(這個是真的空行)

t end
)
:loop
/^$/ {
N
/^\n$/D
t loop
}

:end

執行 sed -f blank.sed example.txt
出來

This is a first line.

this is second

this is third.
....

higgly recommend

作者: twf_cc     时间: 2004-8-2 00:00
由于現在正在 Linux 下,又再試了一下 sed ,用來過濾和替換子串,這個bash script
用了 xmessage, 要在 X Window 用


#!/bin/bash
oLC_ALL=$LC_ALL
LC_ALL=C
export LC_ALL
DATE=$(date +%d)
case "$DATE" in
        0*) DATE=$(echo "$DATE" | sed 's/.//') ;;
         *) ;;
esac
cal |sed "s/\<$DATE\>/*&*/" |xmessage -file "-"
unset LC_ALL
LC_ALL=$oLC_ALL

再一次 feel the power of sed.
DOS ,Win32  一樣有它的用處

作者: Climbing     时间: 2004-8-2 00:00
不错,确实很强大,但有几个问题阻止它被人们接受(包括我):1、版本太多,不同的版本支持不同的参数。2、命令行太复杂,没有一个通俗易懂的说明(尤其是中文说明)。3、太多的转义符号阻止了命令行的可读性,你不知道你会在什么时候掉入符号的陷阱。我看了半天FAQ,还是看不太明白楼上给出的几个例子,这就是这个命令无法应用的明证。
作者: twf_cc     时间: 2004-8-2 00:00
買本名 sed 與 awk 的 書看看,O'Reilly 出版,
中文簡體版由機械工業出版社 出版,

1、版本太多,不同的版本支持不同的参数。
用 POSIX 支援的 sed 版本,任何sed script 用POSIX 寫法一定可行
gnu sed 便可
2、命令行太复杂,没有一个通俗易懂的说明(尤其是中文说明)。
一點不複杂, 你沒看深入吧。

3、太多的转义符号阻止了命令行的可读性,你不知道你会在什么时候掉入符号的陷阱。
转义符号 不多, 你沒看過 perl 吧﹖
我看了半天FAQ,还是看不太明白楼上给出的几个例子,这就是这个命令无法应用的明证。
                                                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
只能說你不會,不是無法應用,sed 由 1978(?) 出現于 Unix,到今天
是 *nix 標準工具之一,Perl 是 sed, awk, shell ,C 的superset,怎會無用﹖
先學 regexp (正規表達式) 吧,用   XP 的 findstr 玩玩 如沒 *nix 的 grep






作者: Climbing     时间: 2004-8-2 00:00
我本来就是不会,我也知道有什么所谓的正则表达式(即sed faq中的RE,但具体却不太明白)。但很难解释的是我在Gnu Sed及Super-Sed下,你所给出的这条命令均无法通过:D:\XYF\System\dos>ipconfig | sed "s/IP Address/!d;s/.*: //"
sed: -e expression #1, char 19: Unknown option to `s'D:\XYF\System\dos>ipconfig | sed "s/IP Address/!d;s/.*://"
sed: -e expression #1, char 19: Unknown option to `s'D:\XYF\System\dos>ipconfig | ssed "s/IP Address/!d;s/.*://"
ssed: -e expression #1, char 19: Unknown option to `s'D:\XYF\System\dos>sed -V
GNU sed version 4.0.9
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.D:\XYF\System\dos>ssed -V
super-sed version 3.59
based on GNU sed version 3.02.80Copyright (C) 1999 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.如果你连这么一个基本的命令不能运行也解释不明白的话,我就无话可说了。
作者: Climbing     时间: 2004-8-2 00:00
经过无数次的试验,这个命令倒是可以用的:ipconfig | sed -n "s/   IP Address*.*: //p"我大概解释一下意思:-n::表示除了用p指定的内容外,不打印其它内容
s:表示替换
"/   IP Address*.*: ":注意引号中的内容,表示查找“以三个空格开头后面跟着IP Address字符串,然后后面跟着*.*(表示任意字符串但包括一个.),再然后跟着一个“: ”(冒号+空格)”这样一行。
"[s/...]/":表示将上面查找的内容替换为空,中括号中的内容表示上文的内容。
"[s/.../]/p":表示将余下的内容打印出来(正好就是IP地址了)。我知道我这样写的命令很不规范,但总比没有任何结果(或者只有错误结果)要好一些。
作者: twf_cc     时间: 2004-8-2 00:00
sorry for using english cause in gb windowsXp
D:\XYF\System\dos>ipconfig | sed "s/IP Address/!d;s/.*: //"  some typo on my post
                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^
should be
ipconfig | sed "/IP Address/!d;s/.*: //"
means   find the string "IP Address" dont delete and then replace all letter in front of   : and a space with
nothing , remain  string or whatever after :
you may test how many dlls in C:\WINDOWS\systen32\
under cmd
cd C;\WINDOWS\system32
dir | sed "/dll$/!d" | sed -n "$="
I got 1228 dlls
or
dir | findstr "dll$" | sed -n "$="


作者: twf_cc     时间: 2004-8-2 00:00
some common use of sed
Under cmd.exe
How many file in current dir
dir | sed -n "$="
I want 1 line output to terminal like Unix `head'  head -n1
sed "1q" your_file.txt
I want to delete  email header
sed "1,/^$/d" whatever.eml
I want to remain email header
sed "/^$/,$d" whatever.eml
I want the last line dont delete
sed "$!d" whatever.txt
I want to replace all `girl' string with `boy' in a txt
sed "s/\<girl\>/boy/g" your.txt
...........

many many use of sed


作者: Climbing     时间: 2004-8-2 00:00
呵呵,你上面的命令的用法我倒还能看懂。你有一条命令有错误,就是看文件的第一行或者前几行(实际上可以自由发挥):sed -n "1p" somefile.txt      # 看第一行sed -n "3,5p" somefile.txt    # 看3到5行如果我想看文件最后几行如何写?说来说去,sed faq把问题搞复杂了,其实你摁住一个版本的sed,把它的用法讲明白了,然后再讲一下其它版本的有什么不同就容易理解了,但写faq的人弱智,搞的人头晕为止。我现在不明白的有这么几点:1、正则表达式都有哪些规则。我在网上没有找到文档,sed faq中提供的那个链接失效了,估计用google可以搜索到。2、sed中跟在那些/或者//的命令都有哪些,例如p表示打印,d表示删除,!d表示不删除,g表示global(全局)等。没有一个地方介绍完全,包括sed faq。其实学这东西也不复杂,只要找一个写的比较经典的例子从头讲到尾就可以了。
作者: twf_cc     时间: 2004-8-2 00:00
q is quit
sed '1q' is equal to sed -n "1p"
now I have write some regexp explaination, of course, not really good
sed have 25 commands(may be wrong,i didnt check manual) , goto google find it out
----------------------------------------------------------------------------------------
从 findstr 的 help 看 正规表达式与 sed 的使用
一般表达式的快速参考:
  .        通配符: 任何字符
  *        重复: 以前字符是或类别出现零或零以上次数
  ^        行位置: 行的开始
  $        行位置: 行的终点
  [class]  字符类别: 任何在字符集中的字符
  [^class] 补字符类别: 任何不在字符集中的字符
  [x-y]    范围: 在指定范围内的任何字符
  \x       Escape: 元字符 x 的文字用法
  \<xyz    字位置: 字的开始
  xyz\>    字位置: 字的结束
  under cmd.exe WinxP
. ex:
sed "s/./-/" 表示 a-z A-Z 0-9 %$#! etc 替换成 -
如 C:\echo "abcd" | sed "s/./-/"
-bcd
* ex:
sed "s/aa*/b/g" 表示  至少一个a , 或更多的a , * 是前字符a
的零个或更多出现,  `g'的meaning 是全体替换
C:\echo "aaaaabbbbccc" | sed "s/aa*/e/"
ebbbbccc
^ ex:
sed -n "/^a.*/p" 表示 由行的开始是a ,在后面是任何字符打印
C:\ipconfig | sed -n "/^W.*/p" `p' 是sed 打印命令
Windows IP Configuration
$ ex:
sed "s/Linux$/Windows/" 行的终点字符 `Linux' 替换成 Windows
如有一个名 junk.txt , 内容是
I Like Linux
Dos is better then Linux

sed "s/Linux$/Windows/g" junk.txt   `g'的meaning 是全体替换
I like Windows
Dos is better then Windows
[class] ex:
任何在字符集中的字符, [a-z] [A-Z] [0-9] [a-zA-Z0-9] ,
C:\> date /t | sed "s/[0-9][0-9]*-[0-9][0-9]*-[0-9][0-9]* //"
[0-9]  仅仅 是 0,1,2,3,4,5,6,7,8,9 任何一个
[^class] ex:
sed "s/<[^>][^>]*>*//"   <[^>][^>]> 是表达 html tags ,
[^>] 那是除了 `>' 是任何字符, html tags 是 <br> </br>
<html>whatever </html>
sed "s/<[^>][^>]*>*//g" whatever.html > whatever.txt
脱去所有 html tags
\x 不知道是不是
\n ==> newline
\t ==> tab
\r ==> return
\v ==> vertical tab
.........
\<xyz ex:
\<xyz 字符边缘 \<Linux 表示  `L' 字前不会匹配 其他的字符
因为 /Linux/ 可以匹配 muLinux
xyz\>   是 \<xyz 对立面  Linux\> `x'之后没有字匹配,
因为 /Linux/ 可以匹配 Linuxer
/\<Linux\>/ 只有匹配Linux
ipconfig | sed -n "/\<E.*/p"  
ipconfig | sed -n "/.*n\>/p"
ipconfig | sed -n "/\<IP\>/p"

findstr 是 Unix 的 `grep' 在WindowsXP的 替代,
使用基本正规表达式, sed 正规表达式比较多 ,
\{n,m\} ,\(regexp\)  是 findstr 没有的.
但是无法用gb chinese input, 只能 copy and paste
加上我功力有限, so, stop here for my post 备注
  





   

作者: twf_cc     时间: 2004-8-3 00:00
some addon to \x for findstr, already remember
\x  逃脱字符特殊的意义
\$ 只有匹配 $
sed "/^\$.*/!d" 含意行的开始是 $,(字面意义,不是行的终点) !d ==> not delete





作者: twf_cc     时间: 2004-8-3 00:00
and some common regexp
/^$/ ==> 空行
[a-zA-Z]*\.*[A-Za-z]*\.*[a-zA-Z]*\.*[A-Za-z]* ==> web site 地址
/<[^>][^>]*>*/ ==> html tags
.* 零个or 更多的任何字符
......

few example , regexp 是许多的 programming language 的基本语法,也许
增加许多的伸展, 但方法没有改变, like awk , perl...etc
多了 ? , + 的 方法, learning it is the first step for learning programming language



作者: Climbing     时间: 2004-8-3 00:00
前面你讲的基本上是BRE(或者包含部分ERE)的用法,我对正则表达式基本上已经明白是什么意思了,这个不用多解释,正则表达式复杂就复杂在那些元字符及匹配模式上,搞清楚了就很简单(只是比较难以阅读罢了)。前面有一个网友提出一个问题,就是将一个目录下的所有文件名改名去掉第一个字符,这应该可以用sed来实现,不知道楼主可不可以给出一个用sed的解决办法(我已经用lmod解决了)。
作者: twf_cc     时间: 2004-8-3 00:00
我不會寫 batch ,給你一個用 bash script 的方法 , 2.0X above
可用 cygwin 執行, Not test,
1) use sed
#!/bin/bash
for oldname in * ; do
newname=$(echo $i | sed '/.//')
mv $oldname $newname
done
2)  no sed , using bash
#!/bin/bash
for oldname in * ; do
newname=${oldname:1}
mv $oldname $newname
done
3)  give argument on command line , using cut,  usage:  $0  *.txt
#!/bin/bash
file=$1
while [ -n "$file" ] ; do
newname=$(echo $file |cut -b2- )
mv $file $newname
shift
done






作者: twf_cc     时间: 2004-8-3 00:00
typo ,
for oldname in * ; do
newname=$(echo $i | sed '/.//')
mv $oldname $newname
done
should be

for oldname in * ; do
newname=$(echo $i | sed 's/.//')
mv $oldname $newname
done


作者: twf_cc     时间: 2004-8-3 00:00
many many typo

for oldname in * ; do
newname=$(echo $i | sed 's/.//')
mv $oldname $newname
done

should be

for oldname in * ; do
newname=$(echo $oldname | sed 's/.//')
mv $oldname $newname
done


作者: Climbing     时间: 2004-8-3 00:00
我们现在不是在讨论使用Unix来解决问题,我只是在讨论使用sed来解决这个问题,我给出你条件,你不用关心如何使用batch来实现。

命题如下:
1、假设当前目录有一个文件名为 Aneed.ren,当然,在实际情况中会有很多文件。
2、使用dir /b命令,该命令会输出:Aneed.ren。
3、要求使用dir /b | sed "???" 命令输出这样一串字符串:ren "Aneed.ren" "need.ren"

我已经试了一天了,就是找不到怎么把两个字符串连接起来的命令。
我用:dir /b | sed "s/^/ren \"/g;s/$/\"/g"
输出:ren "Aneed.ren"
我用:dir /b | sed "s/^./\"/g;s/$/\"/g"
输出:"need.ren"

但我怎么将两个命令的输出结果连成一行呢?最理想的时候我使用命令:
dir /b | sed -n "s/^/ren \"/g;s/$/\"/gp;s/ren \"./\"/gp"
输出:
ren "Aneed.ren"
"need.ren"

注意,输出结果变为了两行,我知道变成两行的原因就出在第一个p上,p打印时应该是带换行符的,我怎么做才能在一个命令中将两个输出变为一行呢?请指教!

[ Last edited by willsort on 2005-10-14 at 16:06 ]
作者: Climbing     时间: 2004-8-3 00:00
连蒙带骗再晕着,我终于使用sed实现了上述要求,但还是需要一个sed的script文件来配合,这个script文件我命名为ren.sed,内容如下:
:join
/ren/{N
s/\"\n/\" /
}
然后最终用到的命令行是:dir /b | sed -n "s/^/ren \"/g;s/$/\"/gp;s/ren \"./\"/gp" | sed -f ren.sed进一步改善,为了防止文件基本名只有一个字符的文件被改名,进一步修改ren.sed如下:
:join
# 下面一行验证文件基本名是否只有一个字符,将不符合条件的剔出去
# 但这里我却找不到用什么字符在\(?\)中表示任意一个字符的元字符,“.”在这里是无效的
# 所以只好用一个笨办法用[a-zzA-Z0-9_%!@#$-]来表示,但&字符却不能用
/ren \"\([a-zA-Z0-9_%!@#$-]\)\{2,\}[\.\"]/{
N
s/\"\n/\"/
p
}
DOS下的命令行又变为:dir /b | sed -n "s/^/ren \"/g;s/$/\"/gp;s/ren \"./\"/gp" | sed -n -f ren.sed
作者: Climbing     时间: 2004-8-3 00:00
要最终完成前面所要求的将一个目录下所有文件改名时去掉第一个字符的命令应该是:
dir /b | sed -n "s/^/ren \"/g;s/$/\"/gp;s/ren \"./\"/gp" | sed -n -f ren.sed > %tmp%\temp.bat
call %tmp%\temp.bat
del %tmp%\temp.bat这个命令不知道要比用lmod复杂多少倍,所以说在DOS下做什么跟你所选用的工具有很大的关系,我不是说sed不好,但至少在这个特定的要求下它要比lmod差远了,当然,可能高手有更高明的实现办法,我拭目以待。在这里感谢twf_cc朋友的不断鼓励和耐心解释,他鼓励我彻底的学习了一下正则表达式在搜索和替换中的应用。
作者: twf_cc     时间: 2004-8-3 00:00
dir /b | sed -n "s/^/ren \"/g;s/$/\"/gp;s/ren \"./\"/gp"
sorry ,I cannot understand  this
I ran this command the sed complain
dir /b  | sed "s/.//" ===>  geen.ren
but I dont know how to combine it to rename in batch
ok ,strip newline in a text  with sed
say a file contain some content like this
a
b
c
d
I want to make it `abcd'
I would like to use
sed -e ":a" -e "N;s/\n//;ta"  file
I run this on cygwin and cmd.exe no problem, it is a lebel :a to a sed command N ,Next line ,  replace
\n ==> newline ; go back to command until newline disapper. It is a loop
sed got some pattern space , hold space,but I cant explain clear with english or chinese
I learn it base on a book sed & awk 2 years ago, the book show it with picture , I got a long
time to understand it , some command like x ,I never use
using sed in cmd.exe to I am not very expericenced,sorry
may be dir /b | sed -n "s/^/ren \"/g;s/$/\"/gp;s/ren \"./\"/gp" |  sed -e ":a" -e "N;s/\n//;ta"
just guess

usually I run Cygwin with all XP command
if batch can make something like  bash
put the command result to the varilable ,     
set something  = " we run the command in here and the result is for something"
using for loop , I know batch have
for %%i in (*.txt) do
set something  = " we run the command in here and the result is for something"
set something = ``dir /b | sed "s/.//" ''
ren %i %something

that is the easy  way  I think  


作者: twf_cc     时间: 2004-8-3 00:00
every tools got their use,  sed is very power with scripting , of course,
it may not be use in everywere , It just a tool for us to solve problem .
some PS for my bash script
It may change

刚才测试一下我随意写的 bash 脚本,
1,2 没有问题,运行後脚本本身亦改了名 ,3 出现问题, while
loop 改副档较好,所以 重新post , 哈哈,都是 not test 问题, so

#!/bin/bash
#usage :$0 file(s)
for oldname in $@
do
newname=$(echo $oldname | cut -b2-)
mv $oldname $newname
done






作者: wchong     时间: 2004-8-4 00:00
SORRY!我不太懂。
作者: Climbing     时间: 2004-8-4 00:00
这位twf_cc大侠的英文实在太好,所以很多时候都是中英文混合表达思想,英文比中文表达的还要明白,这还是为了照顾我们初学者,否则就是全英文啦。pf!当然,这位朋友肯定是Unix高手,不知道为什么浪迹到了DOS论坛。
作者: lxmxn     时间: 2006-10-26 11:57

  太强了。

  特意把这个帖子顶起来,让大家学习一下sed命令的使用语法。

作者: electronixtar     时间: 2006-10-26 21:08
看完了两页天书的路过
作者: 9527     时间: 2006-10-26 22:14
我从来就是路过,根本就没有仔细看,因为没有时间,做个记号在说吧...留着以后在看
作者: ceii     时间: 2007-3-3 10:39
我觉得19楼的问题本来可以很简单的,为什么搞得那么复杂?
dir /b | sed -r "s/.(.*)/ren & \1/"
作者: vkill     时间: 2007-3-3 11:45
英语太好了