BASH -How easily determine how much is in a variable number of such characters - bash

how easily determine how much is in a variable number of such characters
VAR="ddfasf♣dsdad ♣ as dsdsd ♣ sadsd ♣ df"
echo $VAR # result 4
VAR="♣♣ as dsd♣sd ♣ s♣adsd ♣ df"
echo $VAR # result 5
I tried this but it does not work :-(
echo "$(echo $VAR | tr -dc ♣ | wc -c)"
thank you very much

Try:
chars=${VAR//[!♣]}
echo "${#chars}"

The option to delete all but the specified chars in tr is -C
$(echo $VAR | tr -dC ♣ | wc -c)

Related

Wants to generate a random password on Linux server of length 15 characters

String must contain at least 3 uppercase, 3 lowercase, 3 digits and at least 3 special characters.
I searched a lot, but not able to get the required solution.
head /dev/urandom | tr -dc 'A-Za-z0-9-_' | head -c15
This is what I found, but I am able to get the random combination of all.
What i needed is it must output at least 3 characters from each set.
Try this script:
#!/bin/sh
export LC_ALL=C
upp=$(tr -dc 'A-Z' </dev/urandom | head -c3)
low=$(tr -dc 'a-z' </dev/urandom | head -c3)
dig=$(tr -dc '0-9' </dev/urandom | head -c3)
spe=$(tr -dc '!-/' </dev/urandom | head -c3)
res=$(tr -dc '!-}' </dev/urandom | head -c3)
echo "$upp$low$dig$spe$res"
First, the statement export LC_ALL=C makes sure that we are using just plain ASCII. This eliminates potential issues associated with unicode characters.
Next, the variable upp is assigned to 3 upper-case characters. Similarly, low gets three lower-case, $dig gets three digits, spe gets three special characters, and res gets 3 random characters. The echo statement combines all four variables ands prints them.
The above prints the upper case characters first, lower case second, etc. If you want this order mixed up, replace the last line above with:
echo "$upp$low$dig$spe$res" | sed 's/./&\n/g' | shuf | tr -d '\n'
This script uses openssl-rand to get strings of 15 letters/numbers/special characters until the loop breaks when all conditions are met and the password is printed.
#!/bin/bash
until [ -z "$pw+x" ]
do
pw=$(openssl rand -base64 32 | cut -c1-15) &&\
[[ $(sed "s/[^[:upper:]]//g" <<< $pw | wc -c) -gt 3 ]] &&\
[[ $(sed "s/[^[:lower:]]//g" <<< $pw | wc -c) -gt 3 ]] &&\
[[ $(sed "s/[^0-9]//g" <<< $pw | wc -c) -gt 3 ]] &&\
[[ $(sed "s/[[:alnum:]]//g" <<< $pw | wc -c) -gt 3 ]] && break
done
echo "$pw"

count all the lines in all folders in bash [duplicate]

wc -l file.txt
outputs number of lines and file name.
I need just the number itself (not the file name).
I can do this
wc -l file.txt | awk '{print $1}'
But maybe there is a better way?
Try this way:
wc -l < file.txt
cat file.txt | wc -l
According to the man page (for the BSD version, I don't have a GNU version to check):
If no files are specified, the standard input is used and no file
name is
displayed. The prompt will accept input until receiving EOF, or [^D] in
most environments.
To do this without the leading space, why not:
wc -l < file.txt | bc
Comparison of Techniques
I had a similar issue attempting to get a character count without the leading whitespace provided by wc, which led me to this page. After trying out the answers here, the following are the results from my personal testing on Mac (BSD Bash). Again, this is for character count; for line count you'd do wc -l. echo -n omits the trailing line break.
FOO="bar"
echo -n "$FOO" | wc -c # " 3" (x)
echo -n "$FOO" | wc -c | bc # "3" (√)
echo -n "$FOO" | wc -c | tr -d ' ' # "3" (√)
echo -n "$FOO" | wc -c | awk '{print $1}' # "3" (√)
echo -n "$FOO" | wc -c | cut -d ' ' -f1 # "" for -f < 8 (x)
echo -n "$FOO" | wc -c | cut -d ' ' -f8 # "3" (√)
echo -n "$FOO" | wc -c | perl -pe 's/^\s+//' # "3" (√)
echo -n "$FOO" | wc -c | grep -ch '^' # "1" (x)
echo $( printf '%s' "$FOO" | wc -c ) # "3" (√)
I wouldn't rely on the cut -f* method in general since it requires that you know the exact number of leading spaces that any given output may have. And the grep one works for counting lines, but not characters.
bc is the most concise, and awk and perl seem a bit overkill, but they should all be relatively fast and portable enough.
Also note that some of these can be adapted to trim surrounding whitespace from general strings, as well (along with echo `echo $FOO`, another neat trick).
How about
wc -l file.txt | cut -d' ' -f1
i.e. pipe the output of wc into cut (where delimiters are spaces and pick just the first field)
How about
grep -ch "^" file.txt
Obviously, there are a lot of solutions to this.
Here is another one though:
wc -l somefile | tr -d "[:alpha:][:blank:][:punct:]"
This only outputs the number of lines, but the trailing newline character (\n) is present, if you don't want that either, replace [:blank:] with [:space:].
Another way to strip the leading zeros without invoking an external command is to use Arithmetic expansion $((exp))
echo $(($(wc -l < file.txt)))
Best way would be first of all find all files in directory then use AWK NR (Number of Records Variable)
below is the command :
find <directory path> -type f | awk 'END{print NR}'
example : - find /tmp/ -type f | awk 'END{print NR}'
This works for me using the normal wc -l and sed to strip any char what is not a number.
wc -l big_file.log | sed -E "s/([a-z\-\_\.]|[[:space:]]*)//g"
# 9249133

Count the number of digits in a bash variable

I have a number num=010. I would like to count the number of digits contained in this number. If the number of digits is above a certain number, I would like to do some processing.
In the above example, the number of digits is 3.
Thanks!
Assuming the variable only contains digits then the shell already does what you want here with the length Shell Parameter Expansion.
$ var=012
$ echo "${#var}"
3
In BASH you can do this:
num='a0b1c0d23'
n="${num//[^[:digit:]]/}"
echo ${#n}
5
Using awk you can do:
num='012'
awk -F '[0-9]' '{print NF-1}' <<< "$num"
3
num='00012'
awk -F '[0-9]' '{print NF-1}' <<< "$num"
5
num='a0b1c0d'
awk -F '[0-9]' '{print NF-1}' <<< "$num"
3
Assuming that the variable x is the "certain number" in the question
chars=`echo -n $num | wc -c`
if [ $chars -gt $x ]; then
....
fi
this work for arbitrary string mixed with digits and non digits:
ndigits=`echo $str | grep -P -o '\d' | wc -l`
demo:
$ echo sf293gs192 | grep -P -o '\d' | wc -l
6
Using sed:
s="string934 56 96containing digits98w6"
num=$(echo "$s" |sed 's/[^0-9]//g')
echo ${#num}
10
Using grep:
s="string934 56 96containing digits98w6"
echo "$s" |grep -o "[0-9]" |grep -c ""
10

How to get "wc -l" to print just the number of lines without file name?

wc -l file.txt
outputs number of lines and file name.
I need just the number itself (not the file name).
I can do this
wc -l file.txt | awk '{print $1}'
But maybe there is a better way?
Try this way:
wc -l < file.txt
cat file.txt | wc -l
According to the man page (for the BSD version, I don't have a GNU version to check):
If no files are specified, the standard input is used and no file
name is
displayed. The prompt will accept input until receiving EOF, or [^D] in
most environments.
To do this without the leading space, why not:
wc -l < file.txt | bc
Comparison of Techniques
I had a similar issue attempting to get a character count without the leading whitespace provided by wc, which led me to this page. After trying out the answers here, the following are the results from my personal testing on Mac (BSD Bash). Again, this is for character count; for line count you'd do wc -l. echo -n omits the trailing line break.
FOO="bar"
echo -n "$FOO" | wc -c # " 3" (x)
echo -n "$FOO" | wc -c | bc # "3" (√)
echo -n "$FOO" | wc -c | tr -d ' ' # "3" (√)
echo -n "$FOO" | wc -c | awk '{print $1}' # "3" (√)
echo -n "$FOO" | wc -c | cut -d ' ' -f1 # "" for -f < 8 (x)
echo -n "$FOO" | wc -c | cut -d ' ' -f8 # "3" (√)
echo -n "$FOO" | wc -c | perl -pe 's/^\s+//' # "3" (√)
echo -n "$FOO" | wc -c | grep -ch '^' # "1" (x)
echo $( printf '%s' "$FOO" | wc -c ) # "3" (√)
I wouldn't rely on the cut -f* method in general since it requires that you know the exact number of leading spaces that any given output may have. And the grep one works for counting lines, but not characters.
bc is the most concise, and awk and perl seem a bit overkill, but they should all be relatively fast and portable enough.
Also note that some of these can be adapted to trim surrounding whitespace from general strings, as well (along with echo `echo $FOO`, another neat trick).
How about
wc -l file.txt | cut -d' ' -f1
i.e. pipe the output of wc into cut (where delimiters are spaces and pick just the first field)
How about
grep -ch "^" file.txt
Obviously, there are a lot of solutions to this.
Here is another one though:
wc -l somefile | tr -d "[:alpha:][:blank:][:punct:]"
This only outputs the number of lines, but the trailing newline character (\n) is present, if you don't want that either, replace [:blank:] with [:space:].
Another way to strip the leading zeros without invoking an external command is to use Arithmetic expansion $((exp))
echo $(($(wc -l < file.txt)))
Best way would be first of all find all files in directory then use AWK NR (Number of Records Variable)
below is the command :
find <directory path> -type f | awk 'END{print NR}'
example : - find /tmp/ -type f | awk 'END{print NR}'
This works for me using the normal wc -l and sed to strip any char what is not a number.
wc -l big_file.log | sed -E "s/([a-z\-\_\.]|[[:space:]]*)//g"
# 9249133

shell script counting semicolons in a string

I wrote the following code as part of my project work. I need to print i value based on the number of ;(semi colons) in the input string. But the while loop is not getting executed. It is returning errors. I tried lot of alternatives but could not figure it out.
IN="aa;bb;cc;"
c= echo $IN | tr -dc ';' | wc -c
echo $c
i=1
while [ $i -le $c ];
do
echo $i
i=`expr $i + 1`
done
You need to change this:
c= echo $IN | tr -dc ';' | wc -c
to this:
c=`echo $IN | tr -dc ';' | wc -c`
so that echo $IN | tr -dc ';' | wc -c is run, and its output saved in c — just like you're already doing for i later in the script:
i=`expr $i + 1`
Well if you can use awk, it's much shorter and easier:
echo $IN | awk '{ print length(gensub("[^;]","","g",$0)) }'
There's no need for looping once you have a string of ;. The shell can count the characters in a variable for you with ${#variable}.
$ IN="aa;bb;cc;"
$ c=$(echo $IN | tr -dc ';')
$ echo ${#c}
3

Resources