Rename a group of files based on a regex
Suppose you want to rename the name of a group of files that have the following template:
file1_tmp.sh
file2_tmp.sh
...
file99_tmp.sh
and suppose you want to remove the ‘_tmp’ middle part in all the files. We can use the command “rename” or “prename”:
rename 's/_tmp//' *.sh
Redirect the standard error to the standard output
To redirect the standard error of a shell command, just use the following syntax:
ls file-that-does-not-exist 2>&1 | grep file
Or even better not to have on the terminal the standard error just throw it in /dev/null
ls file-that-does-not-exist 2>/dev/null
The standard open or standard streams that are automatically opened are:
- 0 standard input
- 1 standard output
- 2 standard error
Using simple arrays in bash
With Bash to explicitly declare an array you have to use
declare -A mioarray
To have the value of element 5 just write
echo $[mioarray[5]
While to change the value you have to write
mioarray[5]='new value'
${mioarray[*]} o ${mioarray[@]} is expanded by all array values while $[#mionome[@]} is expanded with the length of the array
What can we do with the arrays? For example, store the output of a command whose line we would like to go to a different item.
IFS=$'\n' mioarray=($(ls -alh))
At this point we can print output as
IFS=$'\n' echo "${mioarray[*]}"
Attention: Double quotes are important for not having the output on a single line.
Doing so we could do several tests on the same captured output once.
Using associative arrays in bash
To declare an associative array, you must do so
declare -A mioarray
and as an index you can use a string, this means that
mioarray[test]='aa'
echo ${mioarray[test]} # returns 'aa'
Convert a decimal number to binary from Bash
Suppose we are working on a bash script and that for some need, not too difficult from reality, it is essential to have to convert a number or a decimal variable into a binary number.
There are of course several solutions but the one I propose does not make use of external programs but it is bash in all respects.
First we need to know the maximum value of the binary number to be obtained in Bash or in how many bits it can be included.
We consider that we are talking about a byte and therefore 8 bits and that its binary range will go from 00000000 to 11111111 (from 0 to 255) then we can write:
bin=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
echo ${bin[*]}

The more is done, in fact, to have the result for example of the number 125 or 78 in binary is enough
echo ${bin[125]}
01111101
echo ${bin[78]}
01001110
If the range of the binary number changes, for example if we double or quadruple it is enough that we define the bin variable with one or two more blocks of the type {0..1}.
So summing up, the bin variable will have to contain as many blocks {0..1} based on the maximum binary number to be obtained, that is, if the maximum number is 2n -1 then it will take n groups {0..1}.
As an example if n=10 and therefore 210 -1=1023 the blocks will be 10
bin=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
echo ${bin[1023]}
1111111111
Convert a decimal number to hexadecimal from Bash
As for the faq with the conversion to binary, also in this we make use of the fantastic bash braces extensions to convert to hexadecimal.
So, always considering the bash faq on the binary we start initially by converting a decimal number between 0 and 255 which corresponds to a hexadecimal digit between 0 and FF:
hex=({{0..9},{a..f}}{{0..9},{a..f}})
echo ${hex[*]}

At this point to get the result of the number 200 or 21 is enough
echo ${hex[200]}
c8
echo ${hex[21]}
15
If the range of the hexadecimal number changes, for example if we double or quadruple it is enough that we define the hex variable with one or two more blocks of the type {0..9}, {a..f}.
So summing up, the hex variable will have to contain many blocks {0..9}, {a..f} based on the maximum binary number to be obtained, that is, if the maximum number is 16n -1 then it will take n groups {0. .9}, {a..f}.
As an example if n=4 and therefore 164 -1=65535 the blocks will be 4
hex=({{0..9},{a..f}}{{0..9},{a..f}}{{0..9},{a..f}}{{0..9},{a..f}})
echo ${hex[60000]}
ea60
echo ${hex[37]}
0025
How to convert an IPV4 netmask to CIDR
To switch from an IPV4 netmask to the equivalent CIDR it might occur to do the simplest thing, that is to use a nested “case” block or “if” to obtain the equivalent CIDR so much so that the available netmasks or CIDR are only 32 and that is
Netmask | Address/CIDR | Adresses |
255.255.255.255 | a.b.c.d/32 | 20 |
255.255.255.254 | a.b.c.d/31 | 20 |
255.255.255.252 | a.b.c.d/30 | 21 |
255.255.255.248 | a.b.c.d/29 | 22 |
255.255.255.240 | a.b.c.d/28 | 23 |
255.255.255.224 | a.b.c.d/27 | 24 |
255.255.255.192 | a.b.c.d/26 | 25 |
255.255.255.128 | a.b.c.d/25 | 26 |
255.255.255.0 | a.b.c.0/24 | 27 |
255.255.254.0 | a.b.c.0/23 | 28 |
255.255.252.0 | a.b.c.0/22 | 29 |
255.255.248.0 | a.b.c.0/21 | 210 |
255.255.240.0 | a.b.c.0/20 | 212 |
255.255.224.0 | a.b.c.0/19 | 213 |
255.255.192.0 | a.b.c.0/18 | 214 |
255.255.128.0 | a.b.c.0/17 | 215 |
255.255.0.0 | a.b.0.0/16 | 216 |
255.254.0.0 | a.b.0.0/15 | 217 |
255.252.0.0 | a.b.0.0/14 | 218 |
255.248.0.0 | a.b.0.0/13 | 219 |
255.240.0.0 | a.b.0.0/12 | 220 |
255.224.0.0 | a.b.0.0/11 | 221 |
255.192.0.0 | a.b.0.0/10 | 222 |
255.128.0.0 | a.b.0.0/9 | 223 |
255.0.0.0 | a.0.0.0/8 | 224 |
254.0.0.0 | a.0.0.0/7 | 225 |
252.0.0.0 | a.0.0.0/6 | 226 |
248.0.0.0 | a.0.0.0/5 | 227 |
240.0.0.0 | a.0.0.0/4 | 228 |
224.0.0.0 | a.0.0.0/3 | 229 |
192.0.0.0 | a.0.0.0/2 | 230 |
128.0.0.0 | a.0.0.0/1 | 231 |
0.0.0.0 | 0.0.0.0/0 | 232 |
If we want instead create a function that converts the netmask to CIDR we need to know how to convert a decimal number to binary first.
fromNetmaskToCidr() {
local netmask=$1
local bin=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
local b=''
local n
local cidr
for n in ${netmask//./ }; do
if [ $n -gt 255 ]; then
echo -e "\t[ERROR] netmask $netmask format error in '.$n'. I will use .255 insted of .$n"
n=255
fi
if [ $n -ne 0 -a $n -ne 128 -a $n -ne 192 -a $n -ne 224 -a $n -ne 240 -a $n -ne 248 -a $n -ne 252 -a $n -ne 254 -a $n -ne 255 ]; then
echo -e "\t[ERROR] netmask $netmask format error in '.$n' (it must be 0,128,192,224,240,248,252,254,255). I will use .255 insted of .$n"
n=255
fi
# $b is the binary of $netmask
b=${b}${bin[$n]}
done
# remove right "0" bits from $b
b=${b/%0*}
cidr=${#b}
echo $cidr
}
What we do is convert the 4 octets of the netmask into binary and put them in series in the only variable “b” then remove the 0 bits present on the right of the overall binary number.
Finally, just count the number of bits left to get the CIDR which will then be returned on exit.