4

My .txt file is having lines like below:

1a
1aa
2a
2aa

I want to do a particular task for "a" side and another particular task for "aa" side. To be more precise and clear the task which I am doing for "a" side should not work for "aa" side and similarly the task which I am doing for "aa" side should not work for "a" side.

For exammple:

  • For "aa" side, I want to go to one directory
  • For "a" side, I want to go to more than one directory.

How can I do that in my script?

1
  • You should specify whether you want to apply the actions in the order in which the lines occur, or are happy to process first all a-lines and then all aa-lines. – PJTraill Jul 4 '17 at 20:35
9
grep -xE '[0-9]+a'

Greps for lines that consist exactly of one or more decimal digits followed by a.

grep -xE '[0-9]+aa'

For the variant with aa.

-E is for extended regexps needed for +. With basic regexps and without -x, you can do:

grep '^[0-9]\{1,\}a$'

^ and $ matching respectively at the beginning an end of the line, and \{1,\} being the BRE equivalent of ERE + (some grep implementations also support \+ for that and you could always use [0-9][0-9]*).

10
  • 1
    I don't think you need to match multiple digits between the begin of line and the first a, just checking for a single digit before a is sufficient. The reason is that you want to exclude matching the second a in aa. I.e. [0-9]a$ and [0-9]aa$ are sufficient. – MSalters Jul 4 '17 at 11:36
  • @MSalters, but that would match on foo1a – Stéphane Chazelas Jul 4 '17 at 11:51
  • Indeed, but the question doesn't actually say what should happen with that anyway. In my reading, foo1a_should_ match. The question only talks about the suffix. – MSalters Jul 4 '17 at 11:55
  • 1
    @MSalters, true, which is why I stated explicitly what solutions in the answer do match on. – Stéphane Chazelas Jul 4 '17 at 11:57
  • 1
    @DeepMukherjee, that's a different question from what you asked here. If you have a different question, please ask it separately, but I think you should have enough pointers in this Q&A for you to figure it out. – Stéphane Chazelas Jul 4 '17 at 15:04
3

As the regular expression a also matches "aa", you should handle "aa" first in your script.

Another option is to use perl compatible regexp's (PCREs), grep has a -P option for enabling those, which does come with the warning

This is highly experimental and grep -P may warn of unimplemented features

(at least the version I have, I don't know if they removed the option or changed/removed the warning in newer versions), or you could use perl. Then a regexp like /a(?!a)/ should be useable in the "a" case.

1
2
#!/bin/sh

while read word; do
    case "$word" in
        *aa)    printf 'Got double "a": %s\n' "$word"   ;;
        *a)     printf 'Got single "a": %s\n' "$word"   ;;
        *)      printf 'Got weirdness:  %s\n' "$word"   ;;
    esac
done <file.in

Running this with the example data in file.in:

Got single "a": 1a
Got double "a": 1aa
Got single "a": 2a
Got double "a": 2aa

You could extend this with a loop over your files around the existing while loop:

#!/bin/sh

for name in ./*.in; do
    while read word; do
        case "$word" in
            *aa)    printf 'Got double "a": %s\n' "$word"   ;;
            *a)     printf 'Got single "a": %s\n' "$word"   ;;
            *)      printf 'Got weirdness:  %s\n' "$word"   ;;
        esac
    done <"$name"
done

This is assuming that you input files matches the pattern *.in and are located in the current directory.

1
  • Note that if you want to read just one ($IFS separated with backslash understood as an escaper and line-continuation) word from each line, that would be read word rest_ignored. To read a line IFS= read -r line. With just one argument, that's more read remaining_words – Stéphane Chazelas Jul 4 '17 at 10:31
1

You can match the suffix aa with aa$. Matching the suffix a is a bit harder since logically aa ends with a as well. That's why you need [^a]a$ to match a single a. The [^a] is an inverted character class, it's every character but an a.

1
  • Not a problem, as it is preceded by digits. – PJTraill Jul 4 '17 at 20:35
0

Assuming you mean zero or more digits at the beginning of a line followed by an a (or two digits, we will cover later), then, yes, this command will work:

grep '^[0-9]*a'

Will match all lines in the input file:

$ grep '^[0-9]*a' file
1a
1aa
2a
2aa

If (and I will provide a solution if this is not what you mean) you mean the whole line, then either of this will work:

$ grep   '^[0-9]*a$' file
$ grep -x '[0-9]*a'  file
1a
2a

To force one or more digits, use either of this:

grep    '^[0-9][0-9]*a'
grep    '^[0-9]\{1,\}a'
grep -E '^[0-9]+a'

But if what you mean is to match a line that start with a digit, has one a, and possibly many things more, then: use this:

$ grep '^[0-9]\{1,\}a[^a]' file

Which, for a file like this:

$ cat file
1a
1aa
123a
1234aa
a
aa
2a
2aa
123afgr
123aahtr

Will accept only this lines:

$ grep -E '^[0-9]+a([^a]|$)' file
1a
123a
2a
123afgr

There are several solutions possible for two a's, and this is a simple example:

$ grep -E '^[0-9]+aa([^a]|$)' file
1aa
1234aa
2aa
123aahtr

And, if you remove the start anchor, the match will be anchored to the end:

$ cat file
1a
1aa
123a
1234aa
a
aa
2a
2aa
123afgr
123aahtr
abc20cb1aa
abc20cb1a
abc20cb2aa
abc20cba

$ grep -E '[0-9]+aa([^a]|$)' infile
1aa
1234aa
2aa
123aahtr
abc20cb1aa
abc20cb2aa

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.