Using multiple sed commands

你说的曾经没有我的故事 提交于 2019-12-04 06:02:19

问题


Hi I'm looking to search through a file and output the values of a line that matches the following regex with the matching text removed, I don't need it output to a file. This is what I am currently using and it is outputting the required text but multiple times:

#!/bin/sh

for file in *; do
sed -e 's/^owner //g;p;!d ; s/^admin //g;p;!d ; s/^loc //g;p;!d ; s/^ser //g;p;!d' $file
done

The preferred format would be something like this so I could have control over what happens inbetween:

for file in *; do
    sed 's/^owner //g;p' $file | head -1
    sed 's/^admin //g;p' $file | head -1
    sed '/^loc //g;p' $file | head -1
    sed '/^ser //g;p' $file | head -1
done

An example input file would be the following:

owner sys group
admin guy
loc Q-30934
ser 18r9723
comment noisy fan is something

and the required output is the following:

sys group
guy
Q-30934
18r9723

回答1:


You're giving sed the p (for Print) command several times. It prints the entire line each time. And unless you tell it not to with the -n option, sed will print the line at the end anyway.

You also give the !d command multiple times.

Edited after you added the multiple-sed version: instead of using head -q, just use -n to avoid printing lines you don't want. Or even use q (Quit) to stop processing after printing the bit you do want.

For instance:

sed -n '/^owner / { s///gp; q; }' $file

The {} group the substitution and quit commands together, so that they are both executed if and only if the pattern is matched. Having used the pattern in the address at the beginning, you can leave it out of the s command. So that command is short for:

sed -n '/^owner / { s/^owner //gp; q; }' $file



回答2:


I'd suggest:

sed -n -e '/^owner / { s///; p; }' \
       -e '/^admin / { s///; p; }' \
       -e '/^loc /   { s///; p; }' \
       -e '/^ser /   { s///; p; }' \
    *

sed is perfectly capable of reading many files, so the loop control is unnecessary (you aren't doing per-file I/O redirection, for example) and it's reasonable to list the files after the rest of the sed command (that's the * on its own). If you've got a more modern version of sed (e.g. GNU sed), you can combine the patterns into a single line:

sed -r -n -e '/^(owner|admin|loc|ser) / { s///; p; }' *



回答3:


This might work for (GNU sed):

sed '0,/^owner /{//s///p};0,/^admin /{//s///p};0,/^loc /{//s///p};0,/^ser /{//s///p}' file

Creates a series of toggle switches, one for each of the desired strings. The switches apply once only throughout the file for each string i.e. only the first occurence of each string is printed.

An alternative and depending on file sizes maybe quicker method:

sed -rn '1{x;s/^/owner admin loc ser /;x};/^(owner |admin |loc |ser )/{G;/^(owner |admin |loc |ser )(.*\n.*)\1/!b;s//\2/;P;/\n$/q;s/.*\n//;h}' file

This preps the hold space with the desired strings. For only those lines that contain the desired strings, append the hold space and check if the current line needs to be amended. Match the desired string with the same string in the hold space. If the line has already appeared the match will fail and the line can be disregarded. If the line is yet to be amended, the desired string is removed from the current line and then the first half of the line is printed. If no strings appear in the remaining half of the line the process is over and can be quit. Otherwise remove the first half of the string and replace the hold space with the desired string removed.



来源:https://stackoverflow.com/questions/21639949/using-multiple-sed-commands

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!