Command Line Kung Fu. Hal limbers up in the dojo. To maintain our fighting trim here in the Command Line Kung Fu dojo, we like to set little challenges for ourselves from time to time. Of course, we prefer it when our loyal readers send us ideas, so keep those emails coming! Really.. please oh please oh please keep those emails coming.. I digress. All of the data breaches in the news over the last year got me thinking about credit card numbers. Os X Command Line Find File![]()
This blog will include fun, useful, interesting, security related, non-security related, tips, and tricks associated with the command line. It will include OS X, Linux, and even Windows! Linux / Unix Command Library: find. Learn about its synopsis, description, options, and examples. Detailed description of how to use the command line in Windows and tutorials on writing and using batch files. As many of you are probably aware, credit card numbers have a check digit at the end to help validate the account number. The Luhn algorithm for computing this digit is moderately complicated and I wondered how much shell code it would take to compute these digits. The Luhn algorithm is a right- to- left calculation, so it seemed like my first task was to peel off the last digit and be able to iterate across the remaining digits in reverse order: $ for d in $(echo 1. The "rev" utility flips the order of our digits, and then we just grab everything from the second digit onwards with "cut". We use a little "sed" action to break the digits up into a list we can iterate over. Then I started thinking about how to do the "doubling" calculation on every other digit. I could have set up a shell function to calculate the doubling each time, but with only 1. Then I needed to output the "doubled" digit only every other digit, starting with the first from the right. That means a little modular arithmetic: $ c=0. I've introduced a counting variable, "$c". Inside the loop, I'm evaluating a conditional expression to decide if I need to output the "double" of the digit or just the digit itself. There are several ways I could have handled this conditional operation in the shell, but having it in the mathematical "$((..))" construct is particularly useful when I want to calculate the total: $ c=0; t=0. We're basically done at this point. Instead of outputting the total, "$t", I need to do one more calculation to produce the Luhn digit: $ c=0; t=0. Here's the whole thing in one line of shell code, including the array definition: doubles=(0 2 4 6 8 1 3 5 7 9). Even with all the extra whitespace, the whole thing fits in under 1. Grand Master Ed would be proud. I'm not even going to ask Tim to try and do this in CMD. EXE. Grand Master Ed could have handled it, but we'll let Tim use his Power. Shell training wheels. I'm just wondering if he can do it so it still fits inside a Tweet.. Tim checks Hal's math. I'm not quite sure how Hal counts, but I when I copy/paste and then use Hal's own wc command I get 1. It is less than *2*0. Here is how we can accomplish the same task in Power. Shell. I'm going to use a slightly different method than Hal. First, I'm going to use his lookup method as it is more terse then doing the extra match via if/then. In addition, I am going to extend his method a little to save a little space. PS C: \> $lookup = @((0. This mutli- dimensional array contains a lookup for the number as well as the doubled number. That way I can index the value without an if statement to save space. Here is an example: PS C: \> $isdoubled = $false. PS C: \> $lookup[$isdoubled][6]. PS C: \> $isdoubled = $true. PS C: \> $lookup[$isdoubled][7]. The shortest way to get each digit, from right to left, is by using regex (regular expression) match and working right to left. A longer way would be to use the string, convert it to a char array, then reverse it but that is long, ugly, and we need to use an additional variable. The results are fed into a For. Each- Object loop. Before the objects (the digits) passed down the pipeline are handled we need to initialize a few variables, the total and the boolean $isdoubled variables in - Begin. Next, we add the digits up by accessing the items in our array as well as toggling the $isdoubled variable. Finally, we use the For. Each- Object's - End to output the final value of $sum. PS C: \> ([regex]: :Matches('1. Right. To. Left')) | For. Each- Object. - Begin { $sum = 0; $isdoubled = $false} - Process { $sum += $l[$isdoubled][[int]$_. End { $sum }We can shorten the command to this to save space. PS C: \> $l=@((0. Matches('1. 23. 45. Right. To. Left')) | %{ $s+=$l[$d][$_. According to my math this is exactly 1. I could trim another 2 by removing a few spaces too. It's tweetable! I'll even throw in a bonus version for cmd. C: \> powershell - command "$l=@((0. Matches("1. 23. 45. Right. To. Left')) | %{ $s+=$l[$d][$_. Ok, it is a bit of cheating, but it does run from CMD. Hal gets a little help. I'm honestly not sure where my brain was at when I was counting characters in my solution. Shortening variable names and removing all extraneous whitespace, I can get my solution down to about 1. Happily, Tom Bonds wrote in with this cute little blob of awk which accomplishes the mission. BEGIN{split("0. 24. Here it is with a little more whitespace. BEGIN{ split("0. 24. Tom's getting a lot of leverage out of the "split()" operator and using his "for" loop to count backwards down the string. I have to explicitly set them to zero or the. Anyway, Tom's original version definitely fits in a tweet!
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. Archives
October 2016
Categories |