Bash HackerRank tips

Looping and Skipping

for i in $(seq 1 2 99); do echo $i; done
for number in {1..99..2}; do echo $number; done
echo -e "\n"{1..99..2}
echo -e 1 "\n"{3..99..2}
printf '%s\n' {1..99..2}

A Personalized Echo

name=`cat -`; echo "Welcome $name"
read name
echo "Welcome $name"
printf "Welcome "; cat
sed -r 's/(.*)/Welcome \1/g'
echo "Welcome $(cat)"
echo "Welcome $(cat <&0)"
echo "Welcome $(</dev/stdin)"
xargs -I ^ echo "Welcome" ^

The World of Numbers

echo -e "3\n3" | { read X; read Y; echo $((X + Y)); } 
read x
read y

echo $((x + y))
echo $((x - y))
echo $((x * y))
echo $((x / y))

#!/bin/bash
read X
read Y
printf "%s\n" $X{+,-,*,/}"($Y)" | bc
read x
read y
for i in {+,-,"*",/}
do
    var=$(((x)$i(y)))
    echo $var
done

#!/bin/bash
read x
read y

if [ "$x" -ge "-100" ] && [ "$y" -ge "-100" ] && [ "$x" -le "100" ] && [ "$y" -le "100" ] && [ "$y" -ne "0" ]; then

    echo "$x + $y" | bc
    echo "$x - $y" | bc
    echo "$x * $y" | bc
    echo "$x / $y" | bc
else

    echo "ERROR"

fi

Comparing Numbers

read X
read Y

if (( $X < $Y )); then
    echo 'X is less than Y'
elif (( $X > $Y )); then
    echo 'X is greater than Y'
else 
    echo 'X is equal to Y'
fi

#!/bin/bash
read x
read y
[[ $x -gt $y ]] && echo 'X is greater than Y'
[[ $x -eq $y ]] && echo 'X is equal to Y'
[[ $x -lt $y ]] && echo 'X is less than Y'

Getting started with conditionals

read X;
if [ "${X:0:1}" = "n" -o "${X:0:1}" = "N" ]; then echo "NO"; fi
if [ "${X:0:1}" = "y" -o "${X:0:1}" = "Y" ]; then echo "YES"; fi
read char; echo -e "YES\nNO\n" | grep -i $char
read c
[[ "$c" == [yY] ]] && echo "YES" || echo "NO"

More on Conditionals

read X; read Y; read Z

if (( X == Y && Y == Z )); then echo "EQUILATERAL"
elif (( X == Y || Y == Z || X == Z )); then echo "ISOSCELES"
else echo "SCALENE"
fi
c=$(cat | tr ' ' "\n" | sort -n -u | wc -l)

[ $c -eq 1 ] && echo EQUILATERAL
[ $c -eq 2 ] && echo ISOSCELES
[ $c -eq 3 ] && echo SCALENE
read a
read b
read c

if [ `$a -eq $`b ] && [ `$a -eq $`c ]; then
    echo "EQUILATERAL"
elif [ `$a -eq $`b ] || [ `$a -eq $`c ] || [ `$b -eq $`c ]; then
    echo "ISOSCELES"
else
    echo "SCALENE"
fi

Arithmetic Operations

printf %.3f $({ echo -n "scale=4; "; cat; } | bc)
cat | bc -l | xargs printf "%.3f"
read a
printf "%.3f\n" $(bc -l <<< "$a")

Compute the Average

read n;
readarray -t a_num

printf "%.3f" $({
    echo -n "(";
    { IFS=+; echo -n "${a_num[*]}"; };
    echo -n ") / $n"; } | bc -l)
read n
printf "%.3f" $(echo "("$(cat)")/$n" | tr ' ' '+' | bc -l)
read n
arr=($(cat)) 
arr=${arr[*]}
printf "%.3f" $(echo $((${arr// /+}))/$n | bc -l)
read n
sum=0
for ((i=0;i<$n;i++))
do
    read temp
    sum=`$(($`sum+$temp))
done
printf "%.3f\n" `$(bc -l <<< "$`sum/$n")
read n
for i in $(seq 1 $n);
    do
        read num
        sum=$((sum + num))
    done
printf "%.3f" $(echo "$sum/$n" | bc -l)

Functions and Fractals - Recursive Trees - Bash!

Too long, I passed !

declare -A arr

initialize(){
    for r in {0..62}; do
        for c in {0..99}; do
            arr[$r,$c]="_"
        done
    done
}
print(){
    for r in {0..62}; do
        for c in {0..99}; do
            echo -n ${arr[$r,$c]}
        done
        echo
    done
}

draw(){
    local cnt=$1
    local r=$2
    local c=$3
    for ((i=0; i<cnt; i++ )); do
        arr[$r,$c]=1
        (( r -= 1 ))
    done
    for ((i=0; i<cnt; i++ )); do
        arr[$r,$((c-i-1))]=1
        arr[$r,$((c+i+1))]=1
        (( r -= 1 ))
    done

    if [[ $4 -gt 1 ]]; then
        draw $(($cnt>>1)) $r $(($c-cnt)) $(($4-1))
        draw $(($cnt>>1)) $r $(($c+cnt)) $(($4-1))
    fi
}

initialize

read x
draw 16 62 49 x

print

branch() {    
    if (( $1 == 0 )); then
        exit;
    fi
    let inc=int=ext=rows=$(( 64 / 2**$1 ))
    for ((i=1;i<=rows;i++)) do   
        x=$((buffer))
        for ((j=0;j<100;j++)) do  
            if (( $1 > N )) || (( j >= (100 - buffer) )) || (( j != x )); then
                printf "_"
            else
                printf "1"                
                if (( i <= rows/2 )); then               
                    if (( inc == int )); then
                        inc=$((ext))
                    else
                        inc=$((int))
                    fi  
                fi
                x=$((x+inc))
            fi
        done
        printf "\n"
        if ((i <= rows/2 )); then
            buffer=$((buffer+1))
            int=$((int-2))
            inc=ext=$((ext+2))           
        fi
    done    
    branch $(($1-1))
}
printf "%0.s_" {1..100} 
printf "\n"
buffer=18
read N
branch 5

#!/bin/bash

declare -A m
StartLegLength=16
maxrows=63
maxcols=100
iter=$(cat)


function Y {
  typeset -i row=$1 col=$2 len=$3 iter=$4
  typeset -i r=$row x=$len cl=$col cr=$col l=$((len/2))


# leg
  while (( x-- > 0 ))
  do m[$((r--)),$col]=1
  done


# fork
  x=$len
  while (( x-- > 0 ))
  do m[$r,$((--cl))]=1
     m[$r,$((++cr))]=1
     ((r--))
  done


# subs
  if (( --iter > 0 ))
  then Y $r $cl $l $iter
       Y $r $cr $l $iter
  fi
}


# initialize
for (( row=0; row<maxrows; row++ ))
do  for (( col=0; col<maxcols; col++))
    do  m[$row,$col]=_
    done
done


# recurse
Y $(( maxrows-1 )) $(( (maxcols-1)/2 )) $StartLegLength $iter


# show the result
for (( r=0; r<maxrows; r++ ))
do  for (( c=0; c<maxcols; c++))
    do  printf "%s" ${m[$r,$c]}
    done
    printf "\n"
done

Cut

cut -f1,3 -d":" /etc/passwd
# Field
cut -c1 /etc/passwd
# Char
cut -c1-5 /etc/passwd
cut -b1 /etc/passwd
# Byte
cut -c3
cut -c2,7
cut -c2-7
# Inclusive
cut -c0-4

cut -f1-3 -d$'\t'
# Tab delimiter
cut -f1-3 -s
# Not containg delimiter
cut -c13-
cut -f4 -d" "
cut -f1-3 -d" "
cut -f2-

Middle

sed -n '12,22p'
head -n 22 | tail -n +12
cut -d$'\n' -f12-22
head -22 | tail -11

Tail

tail -n 20
tail -c 20

Tr

tr '()' '[]'
tr -d [a-z]
sed "s/  */ /g"
tr -s  ' ' ' '
# S for squeezze
tr -s " "

Sort

sort
sort -r
sort -n
sort -rn
sort -t$'\t' -nr -k2
sort -r -n -k2 -t $'\t'
# Same
sort -n -t $'\t' -k 2
sort -nr -t '|' -k 2

Uniq

uniq
uniq -c | cut -c7-
uniq -c | tr -s " " | cut -b 2-
# Same
uniq -ci | tr -s " " | cut -b 2-
uniq -u

Paste

tr '\n' ';' | head -c -1
paste -s -d";"
paste -d ";" - - -
paste -sd ';;\n'
paste -s
paste - - -

Array

Read in an Array

arr=($(cat)); echo ${arr[@]}

Slice an Array

  • ${A[@]:3:5}: From 3 (0 indexed) with 5 elements
readarray -t A
B=("${A[@]:3:5}")
echo "${B[*]}"
arr=($(cat))
echo ${arr[@]:3:5}
head -8 | tail -5 | paste -s -d' '

Filter an Array with Patterns

arr=($(cat))
echo ${arr[@]/*[Aa]*/}
grep -vi a

Concatenate an array with itself

arr=($(cat))
echo "${arr[@]} ${arr[@]} ${arr[@]}"
X=$(xargs)
echo $X $X $X
X=$(paste -d' ')
echo $X $X $X
tr `$'\n' ' ' | awk '{print $`0 `$0 $`0}'
IFS=$'\n' read -d '' -ra countries
echo "${countries[@]}" "${countries[@]}" "${countries[@]}"

Display an element of an array

arr=($(cat))
echo ${arr[3]}
awk 'NR==4'

Count the number of elements in an Array

arr=($(cat))
echo ${
#arr[*]}

Remove the First Capital Letter from Each Element

arr=($(cat))
echo ${arr[@]/?/.}

Lonely Integer - Bash!

read n
tr " " "\n" | sort | uniq -u
read
arr=($(cat))
arr=${arr[*]}
# render a new variable of type string from the merging of the array arr delimited by space, i.e., from [1,2,2,2,1] to "1 2 2 2 1"
echo $((${arr// /^}))
# replaces all spaces ' ' in the string variable with ^ (bitwise-XOR operator),
read
echo $(( `tr ' ' '^'` ))

# read the input values
read n
read -a A

#echo -e "The size of the array is '${#A[*]}', and the array is:\n${A[*]}"
x=${A[0]}

#echo "A[0] = ${A[0]}, x = $x"
for (( i = 1; i < ${
#A[*]}; i++ )); do

#for (( i = 1; i < n; i++ )); do
    $((x ^= ${A[i]} ))

#x=$((x ^ ${A[i]} ))

#echo "A[$i] = ${A[i]}, x = $x"

done
echo $x

Grep / Sed / Awk

Grep

  • Note: escape | ()
grep " the "
grep '\bthe\b'
grep -w 'the'
grep -viw that
grep -iw 'the\|that\|then\|those'
grep '\(\d\)\s*\1'

Sed

sed 's/\bthe\b/this/'
sed -e 's/\<the\>/this/'
sed 's/\<thy\>/your/gi'
sed 's/\<thy\>/{\0}/gi'
sed 's/\d\d\d\d \d\d\d\d \d\d\d\d/**** **** ****/'
sed 's/[0-9]\+ /**** /g'
sed -e 's/([0-9]){4} /**** /g'
sed -r 's/[0-9]{4} /**** /g'

# Reverse each line

# Used sed to replace digits with *, starting with the 5th digit

# Reverse each line again
rev | sed 's/[0-9]/*/g5' | rev
sed -E 's/(\d{4}) (\d{4}) (\d{4}) (\d{4})/\4 \3 \2 \1/'
awk '{print $4" "$3" "$2" "$1}'
sed -r 's/(.... )(.... )(.... )(....)/\4 \3\2\1/'

Awk

  • NF Number of Fields
awk '{if ($4 == "") print "Not all scores are available for",$1;}'
awk '{if(NF < 4) print "Not all scores are available for",$1;}'
awk '{if (NF < 4){print "Not all scores are available for "$1}}'
# Removed coma
awk '$4=="" {print "Not all scores are available for " $1} '
awk '{printf $1" : "; if ($2+$3+$4 >= 150) {print "Pass"} else {print "Fail"}}'
# Wrong but I got lucky
awk '{print $1,":", ($2<50||$3<50||$4<50) ? "Fail" : "Pass"}'
awk '{
    printf $0" : ";
    sum=$2+$3+$4;
    if (sum >= 240) {print "A"}
    else if (sum >= 180) {print "B"}
    else if (sum >= 150) {print "C"}
    else {print "FAIL"}
    }'
awk '{avg=($2+$3+$4)/3; print $0, ":", (avg<50)?"FAIL":(avg<80)?"B":"A"}'
  • Concatenate each 2 lines
paste -d";" - -
awk 'ORS=NR%2?";":"\n"'
awk 'NR%2{printf$0";"}1-NR%2'
awk '{
    if ( NR % 2 == 1 )
        printf "%s;", $0
    else
        printf "%s\n", $0  
}'

Awk tricks

awk '/^num/ {n++;sum+=$2} END {print n?sum/n:0}' file