Given the clarification around the rules, and given that the environment is linux and we're using grep, this helps a lot to provide a better answer! :)
The way I would now approach this problem is not with a single regex. The rules are too complicated for this to be elegantly solved with a single simple regex. However, a good starting point it this (assuming the source file is pass.txt):
grep -E -o '[a-zA-Z0-9_$%*@#]{10,}' ./pass.txt
-E for the uninitiated means Extended regex, which essentially means that more regex features such as {} no longer require escaping, so that it's easier to read without all the extra slashes.
-o returns Only the matching part of the file, rather than returning the whole line.
Note the use of single quotes, which is helpful due to the $
character which within double quotes would be interpreted as the start of a variable name. Single quotes means it is treated as a literal.
The flaw with the above regex is that you will match many false positives, such as the last three of the following examples:
Password@1234
sffa##1233P
Moose**F00!d
Dollar$$01234
Dollar$$NoNum
NothingSpecial123
123#@#@123456
Where Dollar$$NoNum
has no numbers, NothingSpecial123
has no special characters, and 123#@#@123456
has no alphabetic characters.
However, we can filter out these false positives by using the pipe (|
) character to chain many grep commands together, and filter out the items that don't have required properties.
For example, to filter out items which do not contain alphabetic characters, we can use the following:
grep -E -o '[a-zA-Z0-9_$%*@#]{10,}' ./pass.txt | grep -E -v '^[^a-zA-Z]+$'
Noticing that we used -o in the first grep, we can now be explicit about matching the start and end of the password by starting with ^
and ending with $
. The match itself is an inverted character class ([^.....]
), which will match any text that is NOT specified in the square brackets. For example, [^a]
will match any character which is NOT a
, so would match b
for instance. In our example here, we are matching anything which is NOT an alphabetic character. Because we are also matching the start and end of the password, if we hit a match, then we know we have a password here which is comprised entirely of text which is NOT alphabetic, which violates rule #4 in that it should contain an alphabetic character.
This however does the opposite of what we want - this will FIND the matches which DO NOT have the alphabetic character. Grep rather helpfully allows us to invert the output with -v though, which is exactly what we want. Consequently the output of the above will filter out matches which do not contain an alphabetic character.
Applying the same principle to the other rules, we get the following final grep command:
grep -E -o '[a-zA-Z0-9_$%*@#]{10,}' ./pass.txt | grep -E -v '^[^a-zA-Z]+$' | grep -E -v '^[^0-9]+$' | grep -E -v '^[^$%*@#]+$'
The filtered output of the previous grep command feeds into the next filter, and the by the end of them all we've removed all the false positives.