Skip to content

Instantly share code, notes, and snippets.

@xaviershay
Created December 19, 2011 00:27
Show Gist options
  • Save xaviershay/1494931 to your computer and use it in GitHub Desktop.
Save xaviershay/1494931 to your computer and use it in GitHub Desktop.
bash golf problem
#!/bin/bash
# Input:
# output this 6
# do not output this 5
# output this 7
#
# Output (and a non-zero exit code):
# output this 6
# output this 7
THRESHOLD=5
cat test_file |
ruby -ne "puts \$_ if \$_.split(' ').last.to_i > \"${THRESHOLD}\".to_i" | \
ruby -e 'out = STDIN.read; puts out; exit(1) if out.length > 0'
@alindeman
Copy link

@adl9 ➜ cat test
output this 6
do not output this 5
@adl9 ➜ awk 'BEGIN { over_threshold = 0 } { if ($NF > ENVIRON["THRESHOLD"]) { print; over_threshold++; } } END { exit over_threshold }' test
output this 6
@adl9 ➜ echo $?
1

@telemachus
Copy link

# Pretty much like alindeman's but over_threshold doesn't need to be predeclared (0 by default, like Perl)
# and the threshold is set in the BEGIN block not the environment
telemachus ❯❯ cat file2.txt 
do not output this 5
do not output this 4
do not output this 3
telemachus ❯❯ awk 'BEGIN { threshold=5 } $NF > threshold { print; boom++ }; END { exit(boom) }' file2.txt
telemachus ❯❯ echo $?
0
telemachus ❯❯ cat file.txt 
output this 6
output this 7
do not output this 5
telemachus ❯❯ awk 'BEGIN { threshold=5 } $NF > threshold { print; boom++ }; END { exit(boom) }' file.txt
output this 6
output this 7
telemachus ❯❯ echo $?
2

@rhunter
Copy link

rhunter commented Dec 19, 2011

If even awk is too much of an external language, rev |cut|rev can get the last column.

$ cat test 
output this 6
do not output this 5
$ (xargs -L1 -I% bash -c '[ $(echo % | rev | cut -d\  -f 1 | rev) -gt $THRESHOLD ] && echo %' | grep . && exit 1 || exit 0 ) < test
output this 6
$ echo $?
1

Or if the character count is more important than readability:

(xargs -L1 -I% bash -c '[ $(echo %|rev|cut -d\  -f1|rev) -gt $THRESHOLD ]&&echo %'|grep .;exit $(($? != 0)))

@floere
Copy link

floere commented Dec 19, 2011

How about:

cat test_file | grep -qv ' [1-5]$'
exit $(($?^1))

This assumes that the threshold can be expressed as a nice regexp.

@xaviershay
Copy link
Author

nice ideas everyone. Inspired by floere, I found a nice way to replace the second ruby incantation in my script:

egrep ".+"

Will probably use awk to replace the first one.

@zaius
Copy link

zaius commented Dec 19, 2011

Not the shortest ever, but all bash:

while read line
do
 val=`echo $line | grep -Eo '[0-9]+'`
 if [[ "$val" -gt "$THRESHOLD" ]]; then
   echo $line
   exit 1
 fi
done

@xaviershay
Copy link
Author

added extra test data to negate early exit solutions.

@xaviershay
Copy link
Author

Combined above solutions to this:

#!/bin/bash

THRESHOLD=5

! cat test_file | \
  awk "\$NF > $THRESHOLD { print }" | \ # $NF = last field
  egrep ".+"                            # Set exit code if no output,
                                        # negated by preliminary `!`

@telemachus
Copy link

You can remove the cat and apply the awk line directly to the test_file - if we're still golfing.

awk "\$NF > $THRESHOLD { print }"  test_file

@floere
Copy link

floere commented Dec 19, 2011

Beautiful! :D

(Whoops! Accidental +1, sorry!)

@i5513
Copy link

i5513 commented Apr 29, 2016

@telemachus , you dont need print statement, it is the default behaviour

awk -v t=$THRESHOLD '$NF > t' test_file

Untested , but i'm sure it work , and less readable but shorter:

awk '$NF>'$THRESHOLD test_file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment