Skip to main content
Improved code. s/-f/-F/ etc. Thanks @Isaac.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=${2:-123456789} ; [ "$1" -ge 2 ] &&  
        grep -ifiF <"$( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                    tee >(rev) )"
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: Adding a 2nd argument can change the 123456789 to any other sequence and the code should still work. For example dqs 4 123456789ABCDEF would search for four digit hexadecimal sequences, (and reverse sequences), and dqs 3 $(printf %s {a..z}) would search for three letter alphabetic sequences.

# search `man bash` for the three most popular words 
# that have 3 three char alphabetic runs
man bash | tr ' ' '\n' | sort | uniq -c | sort -gr  | 
dqs 3 $(printf '%s' {a..z}) | head -3

Output:

     92 first
     76 default
     38 environment

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=${2:-123456789} ; [ "$1" -ge 2 ] &&  
        grep -if <( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                    tee >(rev) )
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: Adding a 2nd argument can change the 123456789 to any other sequence and the code should still work. For example dqs 4 123456789ABCDEF would search for four digit hexadecimal sequences, (and reverse sequences), and dqs 3 $(printf %s {a..z}) would search for three letter alphabetic sequences.

# search `man bash` for the three most popular words 
# that have 3 three char alphabetic runs
man bash | tr ' ' '\n' | sort | uniq -c | sort -gr  | 
dqs 3 $(printf '%s' {a..z}) | head -3

Output:

     92 first
     76 default
     38 environment

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=${2:-123456789} ; [ "$1" -ge 2 ] &&  
        grep -iF "$(eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} |
                    tee >(rev) )"
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: Adding a 2nd argument can change the 123456789 to any other sequence and the code should still work. For example dqs 4 123456789ABCDEF would search for four digit hexadecimal sequences, (and reverse sequences), and dqs 3 $(printf %s {a..z}) would search for three letter alphabetic sequences.

# search `man bash` for the three most popular words 
# that have 3 three char alphabetic runs
man bash | tr ' ' '\n' | sort | uniq -c | sort -gr  | 
dqs 3 $(printf '%s' {a..z}) | head -3

Output:

     92 first
     76 default
     38 environment
More words.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=123456789a=${2:-123456789} ; [ "$@""$1" -ge 2 ] &&  
        grep -if <( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                    tee >(rev) )
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: Adding a 2nd argument can change the a=123456789123456789 to any other sequence and the code should still work. For example a=123456789ABCDEFdqs 4 123456789ABCDEF would search for four digit hexadecimal sequences, (and reverse sequences), and printfdqs -v3 a$(printf %s {a..z}, (note: the -v a assigns the printout to the variable $a)), would search for three letter alphabetic sequences.

# search `man bash` for the three most popular words 
# that have 3 three char alphabetic runs
man bash | tr ' ' '\n' | sort | uniq -c | sort -gr  | 
dqs 3 $(printf '%s' {a..z}) | head -3

Output:

     92 first
     76 default
     38 environment

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=123456789 ; [ "$@" -ge 2 ] &&  
        grep -if <( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                   tee >(rev) )
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: change the a=123456789 to any other sequence and the code should still work. For example a=123456789ABCDEF would search for hexadecimal sequences, (and reverse sequences), and printf -v a %s {a..z}, (note: the -v a assigns the printout to the variable $a), would search for alphabetic sequences.

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=${2:-123456789} ; [ "$1" -ge 2 ] &&  
        grep -if <( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                    tee >(rev) )
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: Adding a 2nd argument can change the 123456789 to any other sequence and the code should still work. For example dqs 4 123456789ABCDEF would search for four digit hexadecimal sequences, (and reverse sequences), and dqs 3 $(printf %s {a..z}) would search for three letter alphabetic sequences.

# search `man bash` for the three most popular words 
# that have 3 three char alphabetic runs
man bash | tr ' ' '\n' | sort | uniq -c | sort -gr  | 
dqs 3 $(printf '%s' {a..z}) | head -3

Output:

     92 first
     76 default
     38 environment
Defined sequences as 2 or more chars, instead of 1 or more.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=123456789 ; [ "$@" -gtge 02 ] &&  
        grep -if <( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                   tee >(rev) )
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: change the a=123456789 to any other sequence and the code should still work. For example a=123456789ABCDEF would search for hexadecimal sequences, (and reverse sequences), and printf -v a %s {a..z}, (note: the -v a assigns the printout to the variable $a), would search for alphabetic sequences.

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=123456789 ; [ "$@" -gt 0 ] &&  
        grep -if <( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                   tee >(rev) )
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: change the a=123456789 to any other sequence and the code should still work. For example a=123456789ABCDEF would search for hexadecimal sequences, (and reverse sequences), and printf -v a %s {a..z}, (note: the -v a assigns the printout to the variable $a), would search for alphabetic sequences.

Using grep, tee, and rev, make a tricky little function full of bash-isms:

dqs() { a=123456789 ; [ "$@" -ge 2 ] &&  
        grep -if <( eval eval printf '%s\\\\n' \\$\\{a:\{0..$((${#a}-$1))\}:$1\\} | 
                   tee >(rev) )
       }

Test it:

dqs 5 < data.log 
1234567
dqs 4 < data.log 
1234
7654
1234567
dqs 3 < data.log 
12365
349874
1234
7654
08767
1234567

How it works:

printf prints a list of sequences of the desired length, (like 123, 234, etc.), tee appends a mirror-image (i.e. right-to-left, or backwards) copy using rev, then grep -f <(...) searches standard input for anything in that list.

To make that list of sequences usually would require a loop, or seq, or even both, but here we cheat by using a bash sequence expression, combined with a substring expansion, and some arithmetic. But it's impossible, because the bash interpreter cannot execute these in the desired order. Therefore eval eval and several strategic \\\s are used to force bash to do things in the right order.

The [ "$@" -gt 0 ] && is not functionally necessary here, but it's safer to have it. It makes sure that dqs has one and only one numeric parameter, or grep won't run. This prevents eval eval from doing anything evil.

Bonus: change the a=123456789 to any other sequence and the code should still work. For example a=123456789ABCDEF would search for hexadecimal sequences, (and reverse sequences), and printf -v a %s {a..z}, (note: the -v a assigns the printout to the variable $a), would search for alphabetic sequences.

Added `-i` to `grep`: might as well be case insensitive given the end example.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54
Loading
More detail.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54
Loading
More detail.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54
Loading
Abstracted code a bit.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54
Loading
More detail.
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54
Loading
Source Link
agc
  • 7.4k
  • 4
  • 25
  • 54
Loading