For example 2211 needs to display 6 but I can't find a command that helps me with it.
I have already tried with cut but that can only cut one at a time.
Works in Debian. Try this:
#!/bin/bash
number="2211"
result=0
for (( i=0; i<${#number}; i++ )); do
echo "number[${i}]=${number:$i:1}"
result=$(( result + ${number:$i:1} ))
done
echo "result = ${result}"
Using a while + read loop.
#!/usr/bin/env bash
str=2211
while IFS= read -rd '' -n1 addend; do
((sum+=addend))
done < <(printf '%s' "$str")
declare -p sum
If your bash is new enough, instead of declare
echo "${sum#A}"
If you have bash version 5.2 (the most recent version to this date):
shopt -s patsub_replacement
n=2211
echo $((${n//?/+&}))
Math variant probably there are more elegant variants
sum=0
num=2211
n=${#num}
for ((i=n-1; i>=0; i--)); {
a=$((10**i))
b=$((num/a))
sum=$((sum+b))
num=$((num-(b*a)))
echo $i $a $b $num $sum
}
3 1000 2 211 2
2 100 2 11 4
1 10 1 1 5
0 1 1 0 6
$ echo $sum
6
Another (Shellcheck-clean) way to do it with arithmetic instead of string manipulation:
#! /bin/bash -p
declare -i num=2211 sum=0
while (( num > 0 )); do
sum+=num%10
num=num/10
done
echo "$sum"
I am trying to create below pattern design in Shell script, i have written below codes for the same but i am not getting expected results. can someone help on this?
Desired output-->
*
**
***
****
*****
#! /bin/sh
for ((i=1; i<=5; i++))
do
for ((j=1; j<=5; j++))
do
if [ $j > 6-$i ]
then
echo -n "* "
elif [ $j == 6-$i ]
then
echo -n "* "
else
echo -n " "
fi
done
echo
done
Current output-->
*****
*****
*****
*****
*****
You will need to use another loop to print the pre-pending spaces.
for ((i=1;i<=5;i++)); # Loop to create 5 lines of text
do
for((k=1;k<=(5-i);k++)); # Loop to padd prepending spaces
do
printf "%s" " ";
done;
for ((j=1;j<=i;j++)); # Loop to create asterix
do
printf "%s" "*";
done;
printf "\n"; # Print the carriage return
done
to make the minimum number of changes to your code to get it working; you need to do number comparison, and number addition in order to get your check statements to work:
for ((i=1; i<=5; i++)) ; do
for ((j=1; j<=5; j++)) ; do
if [ $j -ge $((6-$i)) ] ; then
echo -n "* "
else
echo -n " "
fi
done
echo
done
new output:
*
* *
* * *
* * * *
* * * * *
It doesn't need so much arithmetic, you can use printf to add the padding:
n=5
line=''
char='*'
for ((i=1; i<=n; i++)); do
line+=$char
printf "%*s\n" $n "$line"
done
If you want the triangle leaning the other way:
printf "%-*s\n" $n "$line"
This question already has an answer here:
Write a shell script to print a diamond figure [closed]
(1 answer)
Closed 5 years ago.
The question is: Using Shell script programming, create a script that asks the user to enter a number and then prints the following shape. The number of rows is double the columns and user input determine the size of the diamond.
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* *
*
I've been trying this for days. Any help would bee awesome
#!/bin/bash
w=${1-5}
line() { printf "%$(($1+w))s\n" "$(yes "* " | sed ${1}q | tr -d \\n)"; }
for i in $(seq $w) $(seq $((w-1)) -1 1); do line $i; done
I've wrote smth like this. 'size' variable is actualy 1/4 of whole diamond. But that's cosmetics, and you should be able to fix it:
#!/bin/bash
# reading from stdin
read -p 'Size: ' size
# checking if size is a number
echo $size | grep -q -E '^[0-9]+$' || exit 5
vpos=0
while [[ $vpos -le $(( $size * 2 )) ]] ;
do
hpos=0
while [[ $hpos -le $(( $size * 2 )) ]] ;
do
if [[ $vpos -le $size ]] ;
then
# upper vertical half
if ( [ $hpos -lt $(( $size - $vpos )) ] && [ $hpos -lt $size ] ) || ( [ $hpos -gt $(( $size + $vpos )) ] && [ $hpos -gt $size ] ) ;
then
echo -n ' '
else
echo -n '*'
fi
else
# bottom vertical half
if ( [ $hpos -lt $(( $vpos - $size )) ] && [ $hpos -lt $size ] ) || ( [ $hpos -gt $(( 3 * $size - $vpos )) ] && [ $hpos -gt $size ] ) ;
then
echo -n ' '
else
echo -n '*'
fi
fi
hpos=$((hpos + 1))
done ;
echo ''
vpos=$((vpos + 1))
done
I have written the following code for you, I hope that it helps you:
#!/usr/bin/env bash
#get the first argument passed to your script and assign it to STAR_NUMBER_MAX,
#if it is empty -> default value will be 0
readonly STAR_NUMBER_MAX="${1:-0}"
#check if your STAR_NUMBER_MAX is a number
re='^[0-9]+$'
if ! [[ $STAR_NUMBER_MAX =~ $re ]] ; then
echo "error: your column_size is not a number" >&2; exit 1
fi
#variable that will be used to compute the number of stars to display per line
star_number=0
#variable that will be used in order to know if we have reached the max amount of stars
test_star_max=0
for i in `seq 1 $((2*STAR_NUMBER_MAX +1))`;
do
#print the spaces
for j in `seq $star_number $STAR_NUMBER_MAX`
do
echo -n " "
done
#print the stars
for j in `seq 1 $star_number`;
do
if (( star_number == STAR_NUMBER_MAX )); then
test_star_max=1
fi
echo -n "*"
done
#print the remaining stars
for j in `seq 2 $star_number`;
do
echo -n "*"
done
if (( test_star_max == 0 )); then
star_number=$((star_number + 1));
else
star_number=$((star_number - 1));
fi
echo ""
done
The result of the script is you described.
the task is to write a shell script
inputs are a string and a number
for example,
xxx.sh "Hello World" 3
the input will be
***************
* Hello World *
* Hello World *
* Hello World *
***************
and here is what have I got so far:
function mantra() {
echo "string is $1"
echo "number is $2"
echo $string
echo $PATH
for num in string_length; do
echo "*"
done
}
How do I count the number of characters in the string?
Am I doing right? I am not exactly sure how to pass command-line arguments into my function.Blockquote
The number of characters in your input string is ${#1}
See this page for a short explanation.
#!/bin/sh
function mantra() {
string=$1
num=$2
strlen=${#string}
let strlen=$strlen+2
echo -n "*"
for (( times = 0; times < $strlen; times++ )); do echo -n "*" ; done
echo "*";
}
mantra $1 $2
for (( times = 0; times < $num; times++ )); do
echo "* $string *"
done
mantra $1 $2
How would I do something like:
ceiling(N/500)
N representing a number.
But in a linux Bash script
Why use external script languages? You get floor by default. To get ceil, do
$ divide=8; by=3; (( result=(divide+by-1)/by )); echo $result
3
$ divide=9; by=3; (( result=(divide+by-1)/by )); echo $result
3
$ divide=10; by=3; (( result=(divide+by-1)/by )); echo $result
4
$ divide=11; by=3; (( result=(divide+by-1)/by )); echo $result
4
$ divide=12; by=3; (( result=(divide+by-1)/by )); echo $result
4
$ divide=13; by=3; (( result=(divide+by-1)/by )); echo $result
5
....
To take negative numbers into account you can beef it up a bit. Probably cleaner ways out there but for starters
$ divide=-10; by=10; neg=; if [ $divide -lt 0 ]; then (( divide=-divide )); neg=1; fi; (( result=(divide+by-1)/by )); if [ $neg ]; then (( result=-result )); fi; echo $result
-1
$ divide=10; by=10; neg=; if [ $divide -lt 0 ]; then (( divide=-divide )); neg=1; fi; (( result=(divide+by-1)/by )); if [ $neg ]; then (( result=-result )); fi; echo $result
1
(Edited to switch let ... to (( ... )).)
Call out to a scripting language with a ceil function. Given $NUMBER:
python -c "from math import ceil; print ceil($NUMBER/500.0)"
or
perl -w -e "use POSIX; print ceil($NUMBER/500.0), qq{\n}"
Here's a solution using bc (which should be installed just about everywhere):
ceiling_divide() {
ceiling_result=`echo "($1 + $2 - 1)/$2" | bc`
}
Here's another purely in bash:
# Call it with two numbers.
# It has no error checking.
# It places the result in a global since return() will sometimes truncate at 255.
# Short form from comments (thanks: Jonathan Leffler)
ceiling_divide() {
ceiling_result=$((($1+$2-1)/$2))
}
# Long drawn out form.
ceiling_divide() {
# Normal integer divide.
ceiling_result=$(($1/$2))
# If there is any remainder...
if [ $(($1%$2)) -gt 0 ]; then
# rount up to the next integer
ceiling_result=$((ceiling_result + 1))
fi
# debugging
# echo $ceiling_result
}
You can use awk
#!/bin/bash
number="$1"
divisor="$2"
ceiling() {
awk -vnumber="$number" -vdiv="$divisor" '
function ceiling(x){return x%1 ? int(x)+1 : x}
BEGIN{ print ceiling(number/div) }'
}
ceiling
output
$ ./shell.sh 1.234 500
1
Or if there's a choice, you can use a better shell that
does floating point, eg Zsh
integer ceiling_result
ceiling_divide() {
ceiling_result=$(($1/$2))
echo $((ceiling_result+1))
}
ceiling_divide 1.234 500
Expanding a bit on Kalle's great answer, here's the algorithm nicely packed in a function:
ceildiv() {
local num=$1
local div=$2
echo $(( (num + div - 1) / div ))
}
or as a one-liner:
ceildiv(){ echo $((($1+$2-1)/$2)); }
If you want to get fancy, you could use a more robust version validates input to check if they're numerical, also handles negative numbers:
ceildiv() {
local num=${1:-0}
local div=${2:-1}
if ! ((div)); then
return 1
fi
if ((num >= 0)); then
echo $(( (num + div - 1) / div ))
else
echo $(( -(-num + div - 1) / div ))
fi
}
This uses a "fake" ceil for negative numbers, to the highest absolute integer, ie, -10 / 3 = -4 and not -3 as it should, as -3 > -4. If you want a "true" ceil, use $(( num / div )) instead after the else
And then use it like:
$ ceildiv 10 3
4
$ ceildiv 501 500
2
$ ceildiv 0 3
0
$ ceildiv -10 1
-10
$ ceildiv -10 3
-4
Mathematically, the function of ceiling can be define with floor, ceiling(x) = -floor(-x). And, floor is the default when converting a positive float to integer.
if [ $N -gt 0 ]; then expr 1 - $(expr $(expr 1 - $N) / 500); else expr $N / 500; fi
Ref. https://en.wikipedia.org/wiki/Floor_and_ceiling_functions
You can use jq if you have it installed. It's "sed for JSON", but I find it surprisingly handy for simple tasks like this too.
Examples:
$ echo 10.001 | jq '.|ceil'
11
$ jq -n '-10.001 | ceil'
-10
Floor () {
DIVIDEND=${1}
DIVISOR=${2}
RESULT=$(( ( ${DIVIDEND} - ( ${DIVIDEND} % ${DIVISOR}) )/${DIVISOR} ))
echo ${RESULT}
}
R=$( Floor 8 3 )
echo ${R}
Ceiling () {
DIVIDEND=${1}
DIVISOR=${2}
$(( ( ( ${DIVIDEND} - ( ${DIVIDEND} % ${DIVISOR}) )/${DIVISOR} ) + 1 ))
echo ${RESULT}
}
R=$( Ceiling 8 3 )
echo ${R}
If you have a string representation of a decimal number, bash does support ceiling using printf function like this:
$ printf %.4f 0.12345
0.1235
But if you need to do some math using decimals, you can use bc -l that by default scales to 20 decimals, then use the result with printf to round it.
printf %.3f $(echo '(5+50*3/20 + (19*2)/7 )' | bc -l)
17.929
This is a simple solution using Awk:
If you want the ceil of ($a/$b) use
echo "$a $b" | awk '{print int( ($1/$2) + 1 )}'
and the floor use
echo "$a $b" | awk '{print int($1/$2)}'
Note that I just echo the dividend '$a' as the first field of the line to awk and the divisor '$b' as the second.
Some more concise Awk logic
awk '
function ceil(ip) {
print ip%1 ? int(ip)+1 : ip
}
BEGIN {
ceil(1000/500)
ceil(1001/500)
}
'
Result
2
3
This function wont't add 1, if the division returns a non-floating number.
function ceiling {
DIVIDEND=${1}
DIVISOR=${2}
if [ $(( DIVIDEND % DIVISOR )) -gt 0 ]; then
RESULT=$(( ( ( $DIVIDEND - ( $DIVIDEND % $DIVISOR ) ) / $DIVISOR ) + 1 ))
else
RESULT=$(( $DIVIDEND / $DIVISOR ))
fi
echo $RESULT
}
Use it like this:
echo $( ceiling 100 33 )
> 4
Some more concise Awk logic
awk '
function ceil(ip) {
print ip%1 ? int(ip)+1 : ip
}
BEGIN {
ceil(1000/500)
ceil(1001/500)
}
'
Result
2
3
Using the gorgeous 'printf' 1 will round up to the next integer
printf %.0f $float
or
printf %.0f `your calculation formula`
or
printf %.0f $(your calculation formula)
ref: how to remove decimal from a variable?
Without specifying any function, we can use the following awk script:
echo x y | awk '{ r=$1 % $2; q=$1/y; if (r != 0) q=int(q+1); print q}'
Not sure this one get any logical error or not. Please correct.
If you are already familiar with the Python library, then rather than learn bc, you might want to define this bash function:
pc () { pyexpr="from math import *; print($#)"; python -c "$pyexpr"; }
Then:
pc "ceil(3/4)"
1
but also any valid python expression works:
pc pi / 4
0.7853981633974483
pc "'\n'.join(['Pythagoras said that %3.2f^2 + %3.2f^2 is always %3.2f'
% (sin(ai), cos(ai), sin(ai)**2 + cos(ai)**2)
for ai in [pi / 4 * k for k in range(8)]])"
Pythagoras said that 0.00^2 + 1.00^2 is always 1.00
Pythagoras said that 0.71^2 + 0.71^2 is always 1.00
Pythagoras said that 1.00^2 + 0.00^2 is always 1.00
Pythagoras said that 0.71^2 + -0.71^2 is always 1.00
Pythagoras said that 0.00^2 + -1.00^2 is always 1.00
Pythagoras said that -0.71^2 + -0.71^2 is always 1.00
Pythagoras said that -1.00^2 + -0.00^2 is always 1.00
Pythagoras said that -0.71^2 + 0.71^2 is always 1.00