Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Hi let's say I have a file that looks like this


How do I turn this into a clean list like


Notice that Edward is not in the list

Using linux commands? Probably grep and/or sed

share|improve this question
Are you interested in Edwa and rd? – Ignacio Vazquez-Abrams May 5 '12 at 5:56
I don't think it's possible to discard Edward entirely without a dictionary. – Dennis May 5 '12 at 5:57
If it's impossible, then let's discard Edward and Tim, I don't really understand why it's impossible though, can't I do (if number in the middle then not a word) or something like that with regex? I'm also able to run multiple commands doesn't have to be one in case that helps – user893730 May 5 '12 at 6:08
"If number in the middle": yes, but it is not possible to distinguish between "Edwa4rd" and e.g. "Lisa7anna" without knowing all valid names beforehand in some dictionary. And is "Mary0anne" one invalid (Maryanne) or two valid (Mary, Anne) names? That's the problem that the earlier commenters pointed at. – Daniel Andersson May 5 '12 at 12:13

Try egrep -o '[A-Za-z](.*[A-Za-z])?' < infile | egrep -o '[A-Za-z]+' > outfile for your example.

The first part picks out name-like things (must start with a letter and end with a letter, but may contain anything between them), and then the second egrep filters us down to just the names which are all-letters.

Looking at this, I can already see several avenues on how to create an input that would cause these expressions to fail and not match exactly the correct stuff (well, this will match as it's written to, but you've left ambiguities-- How should ..Richard..<Tim?.. be handled?), but it was easy to put this together based upon the input data-- shell scripting is often less about 100% mathematical correctness for all possible inputs, but rather knowing your input domain and getting the job done with expressions and commands that work well enough for the input you're having to process.

share|improve this answer
With .Net or Java or similar, that works quite well. Something similar can be done with sed on the command line. – Darth Android May 5 '12 at 6:52

The regex ^[^a-zA-Z]*([a-zA-Z]+)[^a-zA-Z]*$ should work.

  1. ^ matches beginning of the line
  2. [^a-zA-Z]* matches zero or more occurrences of a non-letter
  3. [a-zA-Z]+ matches one or more occurrences of a letter
  4. [^a-zA-Z]* matches zero or more occurrences of a non-letter
  5. $ matches end of the line

So, it will ignore leading and following non-letters in a line and only match if there's no non-letter between the first letter and last letter.

The parenthesis indicates a capture group, which is the part we want to extract and print. I originally wrote and tested this for .NET, but here's a sed command. Don't ask me how sed works, I have no idea.

sed -rn 's/^[^a-zA-Z]*([a-zA-Z]+)[^a-zA-Z]*$/\1/p' inputfile

Instead of printing, you can write directly to an output file:

sed -rn 's/^[^a-zA-Z]*([a-zA-Z]+)[^a-zA-Z]*$/\1/w outputfile' inputfile
share|improve this answer
This will not handle lines which contain no letters, allowing them to pass into the output unmodified. – Darth Android May 5 '12 at 18:12
@DarthAndroid It works on his example... the third line of which contains no letters. [a-zA-Z]+ should match at least one letter. It also works on a blank line. Tested with GNU sed 4.2.1. – Bob May 6 '12 at 3:36

Use grep -o '[[:alpha:]]\+' to extract out all the "words".


It's then up to you to determine which ones are names and which are just sequences of letter.

share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .