Swapping character locations in a string (bash) - string

I have encountered an issue where I need to change the order of the characters in a string in bash, in order to get the ICCID of a sim card.
The number I acquire from the modem looks for example like this; 980136010000006187F5. What I need to do is to take the characters in the string in pairs and recite them in reverse. In this example 98 would be 89, 01 would be 10 and so on, finally adding up to 8910631000000016785F which is a correct ICCID number.
I am thinking that this might be possible using sed or a for-loop of sorts, but I've gotten stuck in how to achieve this. Help would be very appreciated!
Regards,
Carl

sed can do it easily.
sed 's/\(.\)\(.\)/\2\1/g' <<<980136010000006187F5
The sed command finds every match to .. (i.e. a pair of characters), capturing them independently, and then replaces them with the two captures in inverse order.

Related

Why am I getting weird and unpredictable behaviour from substrings in bash?

I am making a bash script. I first grab a line with grep from a realtime updating output (top, airodump-ng) then I am trying to parse that line and extract certain substrings. My problem is the ${VAR:start:length} syntax does not work and is unpredictable. I will show some examples,
My original unparsed string is this, I am trying to extract the two Mac addresses (which I made up)
VAR="12:34:56:78:91:23 23:45:67:89:12:34 -37 24e-24e 0 23"
In the script, var is defined by VAR="airodump-ng | grep ... but for this post it is a string literal.
So maybe there is some random whitespace characters messing with it from grep. Anyways, when I try to take substrings of VAR this is what happens,
SUB=${VAR:1:25}
12:34:56:78:91:23 23:45:
Good
SUB${VAR:1:24}
12:34:56:78:91:23 23:45
Good
SUB${VAR:1:23}
12:34:56:78:91:
Bad
You can see now out of nowhere the substring is much shorter than expected, going from 24->23 does not make it one character shorter but 9 shorter. This patter continues, for example, 12, 13, 14 work but 15 is way to short again. The same thing happens with the cut command echo $VAR | cut -c1-25 with the same indexes.
So how can I fix this and why is it happening. Or are there any better solutions to extract these substrings?
.

convert the numbers to their names(1=one etc) with SED command

I need to convert digits to their name ex: 1=one 2=two etc but I can only use SED command. Just the one-digit numbers should change.
sed 's/[1]/one/g; s/[2]/two/g; s/[3]/three/g; s/[4]/four/g; s/[5]/five/g; s/[6]/six/g; s/[7]/seven/g; s/[8]/eight/g; s/[9]/nine/g; s/[0]/zero/g'
Text:
Lo5se eyes get fat shew. Win4ter can indeed letter oppose way change te5nded now. So is imp6rove my charmed picture exposed adapt5ed demands. Received had en4d prod4uced prepared dive5rted strictly off man br55anched. Known 72ye money 6so large decay voice t6here to. Preserved be mr cordially incom88888mode as an. He 3doors qui03ck child an point at. Had sh2a9re vexed front least style off why him.
The result should be:
Lofivese eyes get fat shew. Winfourter can indeed letter oppose way change tefivended now. So is impsixrove my charmed picture exposed adaptfiveed demands. Received had enfourd prodfouruced prepared divefiverted strictly off man br55anched. Known 72ye money sixso large decay voice tsixhere to. Preserved be mr cordially incom88888mode as an. He threedoors qui03ck child an point at. Had shtwoaninere vexed front least style off why him.
With a sed that has -E to enable EREs and recognizes \n as meaning a newline (e.g. GNU sed):
sed -E 's/(^|[^0-9])([0-9])([^0-9]|$)/\1\n\2\n\3/g; s/\n1\n/one/g; s/\n2\n/two/g; s/\n3\n/three/g; s/\n4\n/four/g; s/\n5\n/five/g; s/\n6\n/six/g; s/\n7\n/seven/g; s/\n8\n/eight/g; s/\n9\n/nine/g; s/\n0\n/zero/g' file
Lofivese eyes get fat shew. Winfourter can indeed letter oppose way change tefivended now. So is impsixrove my charmed picture exposed adaptfiveed demands. Received had enfourd prodfouruced prepared divefiverted strictly off man br55anched. Known 72ye money sixso large decay voice tsixhere to. Preserved be mr cordially incommode as an. He threedoors qui03ck child an point at. Had shtwoa9re vexed front least style off why him.
This might work for you (GNU sed):
sed -E 's/[0-9]+/\n&/g;s/\n(.[0-9])/\1/g;s/$/\n1one2two3three4four5five6six7seven8eight9nine0zero/;:a;s/\n(.)(.*\n.*\1([^0-9]+))/\3\2/;ta;P;d' file
Prepend a newline to each group of numbers.
Remove the prepended newline for numbers with more than two digits.
Append a newline and a lookup table to the end of the line.
Use a loop and pattern matching to replace each single digit with its literal, ensuring the lookup table is maintained.
Print the amended current line less the lookup table.

How can I decipher a substitution cipher?

I have a ciphered text file where A=I a=i !=h etc., I know the right substitutions. How can I generate a readable form of the text?
I have read that it's Substitution Cipher
tr 'Aa!' 'Iih'
This performs the following transformations: A→I, a→i, !→h. If you want the other way around as well (A→I, I→A, …), the command is
tr 'Aa!Iih' 'IihAa!'
The N-th character of the first set is converted to the N-th character of the second set. Read man 1 tr for more information.
Please note that GNU tr, which you have on Linux, doesn't really have a concept of multibyte characters, but instead works one byte at a time; so if your substitutions involve non-ASCII multibyte UTF-8 characters, the command won't work as expected.
Use CyberChef or another encryption tool:
Deciphering
is fairly simple. Just select the Substitute operation and put it into the recipe, then place your key in line with your values such that keys and values are lined up in a column.
CyberChef was created by the GCHQ of Britain.
A Google search for "solve substitution cipher" yields several websites which can solve it for you. https://quipqiup.com https://www.guballa.de/substitution-solver

How to edit this file using grep or using cat or using vim or using another tool?

One of my elder brother who is studying in Statistics. Now, he is writing his thesis paper in LaTeX. Almost all contents are written for the paper. And he took 5 number after point(e.g. 5.55534) for each value those are used for his calculation. But, at the last time his instructor said to change those to 3 number after point(e.g. 5.555) which falls my brother in trouble. Finding and correcting those manually is not easy. So, he told me to help.
I believe there is also a easy solution which is know to me. The snapshot of a portion of the thesis looks like-
&se($\hat\beta_1$)&0.35581&0.35573&0.35573\\
&mse($\hat\beta_1$)&.12945&.12947&.12947\\
\addlinespace
&$\hat\beta_2$&0.03329&0.03331&0.03331 \\
&se($\hat\beta_2$)&0.01593&0.01592&0.01591\\
&mse($\hat\beta_2$)&.000265&.000264&.000264 \\
\midrule
{n=100} & $\hat\beta_1$&-.52006&-.52001&-.51946\\
&se($\hat\beta_1$)&.22819&.22814&.22795\\
&mse($\hat\beta_1$)&.05247&.05244&.05234\\
\addlinespace
&$\hat\beta_2$&0.03134&0.03134&0.03133 \\
&se($\hat\beta_2$)&0.00979&0.00979&0.00979\\
&mse($\hat\beta_2$)&.000098&.000098&.000098
I want -
&se($\hat\beta_1$)&0.355&0.355&0.355\\
&mse($\hat\beta_1$)&.129&.129&.129\\
......................................................................
........................................................................
........................................................................
Note: Don't feel boring for the syntax(These are LaTeX syntax).
If anybody has solution or suggestion, please provide. Thank you.
In sed:
$ sed 's/\(\.[0-9]\{3\}\)[0-9]*/\1/g' file
&se($\hat\beta_1$)&0.355&0.355&0.355\\
&mse($\hat\beta_1$)&.129&.129&.129\\
ie. replace period starting numeric strings with at least 3 numbers with the leading period and three first numbers.
Here is the command in vim:
:%s/\.\d\{3}\zs\d\+//g
Explanation:
: entering command-mode
% is the range of all lines of the file
s substitution command
\.\d\{3}\zs\d\+ pattern you would like to change
\. literal point (.)
\d\{3} match 3 consecutive digits
\zs start substitution from here
\d\+ one or more digits
g Replace all occurrences in the line
Concerning grep and cat they have nothing to do with replacing text. These commands are only for searching and printing contents of files.
Instead, what you are looking is substitution there are lots of commands in Linux that can do that mainly sed, perl, awk, ex etc.

How to make a Palindrome with a sed command?

I'm trying to find the code that searches all palindromes in a dictionary file
this is what I got atm which is wrong :
sed -rn '/^([a-z])-([a-z])\2\1$/p' /usr/share/dict/words
Can somebody explain the code as well.
Found the right answer.
sed -n '/^\([a-z]\)\([a-z]\)\2\1$/p' /usr/share/dict/words
I have no idea why I used -
I also don't have an explenation for the \ ater each group
You can use the grep command as explained here
grep -w '^\(.\)\(.\).\2\1'
explanation The grep command searches for the first any three letters by using (.)(.). after that we are searching the same 2nd character and 1st character is occuring or not.
The above grep command will find out only 5 letters palindrome words.
extended version is proposed as well on that page; and works correctly for the first line but then crashes... there is surely some good to keep and maybe to adapt...
Guglielmo Bondioni proposed a single RE that finds all palindromes up to 19 characters long using 9 subexpressions and 9 back-references:
grep -E -e '^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\9\8\7\6\5\4\3\2\1' file
You can extend this further as much as you want :)
Perl to the rescue:
perl -lne 'print if $_ eq reverse' /usr/share/dict/words
Hate to say it, but while regex may be able to cook your breakfast, I don't think it can find a palindrome. According to the all-knowing Wikipedia:
In the automata theory, a set of all palindromes in a given alphabet is a typical example of a language that is context-free, but not regular. This means that it is impossible for a computer with a finite amount of memory to reliably test for palindromes. (For practical purposes with modern computers, this limitation would apply only to incredibly long letter-sequences.)
In addition, the set of palindromes may not be reliably tested by a deterministic pushdown automaton which also means that they are not LR(k)-parsable or LL(k)-parsable. When reading a palindrome from left-to-right, it is, in essence, impossible to locate the "middle" until the entire word has been read completely.
So a regular expression won't be able to solve the problem based on the problem's nature, but a computer program (or sed examples like #NeronLeVelu or #potong) will work.
explanation of your code
sed -rn '/^([a-z])-([a-z])\2\1$/p' /usr/share/dict/words
select and print line that correspond to :
A first (starting the line) small alphabetic character followed by - followed by another small alaphabetic character (could be the same as the first) followed by the last letter of the previous group followed by the first letter Letter1-Letter2Letter2Letter1 and the no other element (end of line)
sample:
a-bba
a is first letter
b second letter
b is \2
a is \1
But it's a bit strange for any work unless it came from a very specific dictionnary (limited to combination by example)
This might work for you (GNU sed):
sed -r 'h;s/[^[:alpha:]]//g;H;x;s/\n/&&/;ta;:a;s/\n(.*)\n(.)/\n\2\1\n/;ta;G;/\n(.*)\n\n\1$/IP;d' file
This copies the original string(s) to the hold space (HS), then removes everything but alpha characters from the string(s) and appends this to the HS. The second copy is then reversed and the current string(s) and the reversed copy compared. If the two strings are equal then the original string(s) is printed out otherwise the line is deleted.

Resources