sed命令的疑问:pattern space? hold space?

ChenQi 发布于 2012/10/11 14:11
阅读 657
收藏 0

哪位osc的朋友可以解释写sed中的这两个概念:pattern space? hold space?

如下是手册中出现的几处。

-n, --quiet, --silent
              suppress automatic printing of pattern space

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.

n N    Read/append the next line of input into the pattern space.

尤其是gGhH这四个命令,感觉有点糊涂。

加载中
0
ChenQi
ChenQi

问题已解决:http://stackoverflow.com/questions/12833714/the-concept-of-hold-space-and-pattern-space-in-sed#comment17363903_12833714

举例:

1. 如何交换奇数行和偶数行?

chenqi@chenqi-OptiPlex-760:~/poky$ echo $'1\n2\n3\n4\n5\n6' | sed -n '1~2h;2~2{p;x;p}'
2
1
4
3
6
5

2. 如何以行位单位反向输出文件?(就像tac)

chenqi@chenqi-OptiPlex-760:~/poky$ echo $'1\n2\n3\n4\n5\n6' | sed -n '1!G;h;$p'
6
5
4
3
2
1

x: 交换hold space和pattern space中内容

h: copy pattern space to hold space

H: append pattern space to hold space

g: copy hold space to pattern space

G: append hold space to pattern space

 

关于第二个命令的详细讲解:

There are three commands here: 1!G, h and $p. 1!G has an address, 1 (first line), but the ! means that the command will be executed everywhere but on the first line. $p on the other hand will only be executed on the last line. So what happens is this:

  1. first line is read and inserted automatically into the pattern space
  2. on the first line, first command is not executed; h copies the first line into the hold space.
  3. now the second line replaces whatever was in the pattern space
  4. on the second line, first we execute G, appending the contents of the hold buffer to the pattern buffer, separating it by a newline. The pattern space now contains the second line, a newline, and the first line.
  5. Then, h command inserts the concatenated contents of the pattern buffer into the hold space, which now holds the reversed lines two and one.
  6. We proceed to line number three -- go to the point (3) above.

Finally, after the last line has been read and the hold space (containing all the previous lines in a reverse order) have been appended to the pattern space, pattern space is printed with p. As you have guessed, the above does exactly what the tac command does -- prints the file in reverse.

0
ChenQi
ChenQi

Some Basics

There is one more "location" to be covered: thehold buffer orhold space. Think of it as a spare pattern buffer. It can be used to "copy" or "remember" the data in the pattern space for later. There are five commands that use the hold buffer.

 

The "x" command eXchanges the pattern space with the hold buffer. By itself, the command isn't useful. Executing the sed command

sed 'x'

as a filter adds a blank line in the front, and deletes the last line. It looks like it didn't change the input stream significantly, but thesed command is modifying every line.

The hold buffer starts out containing a blank line. When the "x" command modifies the first line, line 1 is saved in the hold buffer, and the blank line takes the place of the first line. The second "x" command exchanges the second line with the hold buffer, which contains the first line. Each subsequent line is exchanged with the preceding line. The last line is placed in the hold buffer, and is not exchanged a second time, so it remains in the hold buffer when the program terminates, and never gets printed. This illustrates that care must be taken when storing data in the hold buffer, because it won't be output unless you explicitly request it. 

 

The "H" command allows you to combine several lines in the hold buffer. It acts like the "N" command as lines are appended to the buffer, with a "\n" between the lines. You can save several lines in the hold buffer, and print them only if a particular pattern is found later.

Another example (context grep)

#!/bin/sh
# grep3 - prints out three lines around pattern
# if there is only one argument, exit

case $# in 
	1);;
	*) echo "Usage: $0 pattern";exit;;
esac;
# I hope the argument doesn't contain a /
# if it does, sed will complain

# use sed -n to disable printing 
# unless we ask for it
sed -n '
'/$1/' !{
	#no match - put the current line in the hold buffer
	x
	# delete the old one, which is 
	# now in the pattern buffer
	d
}
'/$1/' {
	# a match - get last line
	x
	# print it
	p
	# get the original line back
	x
	# print it
	p
	# get the next line 
	n
	# print it
	p
	# now add three dashes as a marker
	a\
---
	# now put this line into the hold buffer
	x
}'

用h/H命令来实现:

#!/bin/sh
# grep3 version b - another version using the hold commands
# if there is only one argument, exit

case $# in 
	1);;
	*) echo "Usage: $0 pattern";exit;;
esac;

# again - I hope the argument doesn't contain a /

# use sed -n to disable printing 

sed -n '
'/$1/' !{
	# put the non-matching line in the hold buffer
	h
}
'/$1/' {
	# found a line that matches
	# append it to the hold buffer
	H
	# the hold buffer contains 2 lines
	# get the next line
	n
	# and add it to the hold buffer
	H
	# now print it back to the pattern space
	x
	# and print it.
	p
	# add the three hyphens as a marker
	a\
---
}'

用g/G来实现:

#!/bin/sh
# grep3 version c: use 'G'  instead of H

# if there is only one argument, exit

case $# in 
	1);;
	*) echo "Usage: $0 pattern";exit;;
esac;

# again - I hope the argument doesn't contain a /

sed -n '
'/$1/' !{
	# put the non-matching line in the hold buffer
	h
}
'/$1/' {
	# found a line that matches
	# add the next line to the pattern space
	N
	# exchange the previous line with the 
	# 2 in pattern space
	x
	# now add the two lines back
	G
	# and print it.
	p
	# add the three hyphens as a marker
	a\
---
	# remove first 2 lines
	s/.*\n.*\n\(.*\)$/\1/
	# and place in the hold buffer for next time
	h
}'


 

 

 

 

返回顶部
顶部