Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash -
- #===============================================================================
- #
- # FILE: mlgrep.sh
- #
- # USAGE: ./mlgrep.sh [OPTION]... PATTERN [FILE]...
- #
- # DESCRIPTION: Script provides the ability to search multiline regexp in the
- # file. The algo is simple:
- # 1) store the pattern to search in const buffer
- # 2) read input file line by line into circular buffer
- # 3) as soon as the input buffer is full perform match:
- # a) if match found - print & empty input buffer
- # b) if not - print (in case of invert match) the first line
- # from the buffer
- # 4) when EOF is reached, print (in case of invert match) the
- # rest of the buffer
- #
- # OPTIONS: [-n] - print line numbers
- # [-v] - invert match
- # [-i] - ignore case
- # [-f] - read pattern from file
- # <pattern (file)> - pattern (or the file with pattern) to
- # search, it should have one or several
- # lines in form of regular expressions
- # <input file> - input text file or stdin
- #===============================================================================
- set -o nounset # Treat unset variables as an error
- PRINT_NUM=0
- INVERT=0
- IGNORE_CASE=0
- FROM_FILE=0
- torem=0
- function usage()
- {
- echo -e "Usage: $(basename $0) [OPTION]... PATTERN [FILE]...\nTry \`$(basename $0) -h\` for more information."
- exit 1
- }
- while getopts "nvifh" opt
- do
- case "$opt" in
- n) PRINT_NUM=1;;
- v) INVERT=1;;
- i) IGNORE_CASE=1;;
- f) FROM_FILE=1;;
- h)
- cat << EOF
- $(basename $0) is 'Multiline grep' tool.
- Usage: $(basename $0) [OPTION]... PATTERN [FILE]...
- Search for PATTERN in each FILE or standard input.
- PATTERN is awk-style regular expression ('\n' are
- allowed to represent multiline regexp)
- OPTIONS:
- -n - print line numbers
- -v - invert match
- -i - ignore case
- -f - read pattern from file
- EOF
- exit 0;;
- esac
- done
- shift $(($OPTIND - 1))
- if [ $# -eq 0 ]
- then
- usage
- fi
- if [[ $FROM_FILE -eq 1 && -s "$1" ]]
- then
- PATTERN_FILE="$1"
- else
- PATTERN_FILE=$(mktemp)
- torem=1
- echo -e $1 > $PATTERN_FILE
- fi
- shift
- awk -vprint_num=$PRINT_NUM -vinvert=$INVERT -vignore_case=$IGNORE_CASE -vpattern_file=$PATTERN_FILE 'BEGIN {
- # save pattern to search for from file to const buffer
- patternlen = 0;
- while (getline < pattern_file)
- {
- if (ignore_case)
- pattern[patternlen] = tolower($0);
- else
- pattern[patternlen] = $0;
- patternlen++;
- }
- # user circular buffer
- head = 0;
- tail = 0;
- empty = 1;
- }
- # Increment user circular buffer index
- function increment(count)
- {
- if (count == (patternlen - 1))
- count = 0;
- else
- count++;
- return count;
- }
- # Whether user buffer is full
- function isfull()
- {
- if (increment(tail) == head)
- return 1;
- else
- return 0;
- }
- {
- # Add current string to circular buffer and move indexes if necessary
- if (!empty)
- {
- if (isfull())
- head = increment(head);
- tail = increment(tail);
- }
- buf[tail] = $0;
- empty = 0;
- # Check current buffer against the saved pattern;
- # check makes sense only if buffer is full
- if (isfull())
- {
- equal = 1;
- j = head;
- for (i = 0; i < patternlen; i++)
- {
- if (ignore_case)
- {
- if (!match(tolower(buf[j]),pattern[i]))
- {
- equal = 0;
- break;
- }
- }
- else
- {
- if (!match(buf[j],pattern[i]))
- {
- equal = 0;
- break;
- }
- }
- j = increment(j);
- }
- # Behaviour depends on what is needed: print only found or print all
- # but found
- if (equal)
- {
- if (!invert)
- {
- j = head;
- if (print_num)
- {
- for (i = 0; i < patternlen; i++)
- {
- printf "%d:%s\n", NR - patternlen + i + 1, buf[j];
- j = increment(j);
- }
- }
- else
- {
- for (i = 0; i < patternlen; i++)
- {
- printf "%s\n", buf[j];
- j = increment(j);
- }
- }
- }
- empty = 1;
- head = tail;
- }
- else if (invert)
- {
- if (print_num)
- printf "%d:%s\n", NR - patternlen + 1, buf[head];
- else
- print buf[head];
- }
- }
- }
- END {
- # Need to print out what is left in the user buffer.
- # No need to print anything if the pattern has just been found
- if (!empty && invert)
- {
- if (!isfull())
- {
- if (print_num)
- {
- buflen = 0;
- for (j = head; increment(tail) != j; j = increment(j))
- buflen++;
- i = 0;
- for (j = head; increment(tail) != j; j = increment(j))
- {
- printf "%d:%s\n", NR - buflen + i + 1, buf[j];
- i++;
- }
- }
- else
- {
- for (i = head; ; i = increment(i))
- {
- print buf[i];
- if (i == tail)
- break;
- }
- }
- }
- else
- {
- if (print_num)
- {
- i = 1;
- for (j = increment(head); j != head; j = increment(j))
- {
- printf "%d:%s\n", NR - patternlen + i + 1, buf[j];
- i++;
- }
- }
- else
- {
- for (j = increment(head); j != head; j = increment(j))
- {
- print buf[j];
- }
- }
- }
- }
- }' $*
- if [ $torem -eq 1 ]
- then
- rm $PATTERN_FILE
- fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement