uppercase first character in a variable with bash - bash

I want to uppercase just the first character in my string with bash.
foo="bar";
//uppercase first character
echo $foo;
should print "Bar";

One way with bash (version 4+):
foo=bar
echo "${foo^}"
prints:
Bar

foo="$(tr '[:lower:]' '[:upper:]' <<< ${foo:0:1})${foo:1}"

One way with sed:
echo "$(echo "$foo" | sed 's/.*/\u&/')"
Prints:
Bar

$ foo="bar";
$ foo=`echo ${foo:0:1} | tr '[a-z]' '[A-Z]'`${foo:1}
$ echo $foo
Bar

To capitalize first word only:
foo='one two three'
foo="${foo^}"
echo $foo
One two three
To capitalize every word in the variable:
foo="one two three"
foo=( $foo ) # without quotes
foo="${foo[#]^}"
echo $foo
One Two Three
(works in bash 4+)

Using awk only
foo="uNcapItalizedstrIng"
echo $foo | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}'

Here is the "native" text tools way:
#!/bin/bash
string="abcd"
first=`echo $string|cut -c1|tr [a-z] [A-Z]`
second=`echo $string|cut -c2-`
echo $first$second

just for fun here you are :
foo="bar";
echo $foo | awk '{$1=toupper(substr($1,0,1))substr($1,2)}1'
# or
echo ${foo^}
# or
echo $foo | head -c 1 | tr [a-z] [A-Z]; echo $foo | tail -c +2
# or
echo ${foo:1} | sed -e 's/^./\B&/'

It can be done in pure bash with bash-3.2 as well:
# First, get the first character.
fl=${foo:0:1}
# Safety check: it must be a letter :).
if [[ ${fl} == [a-z] ]]; then
# Now, obtain its octal value using printf (builtin).
ord=$(printf '%o' "'${fl}")
# Fun fact: [a-z] maps onto 0141..0172. [A-Z] is 0101..0132.
# We can use decimal '- 40' to get the expected result!
ord=$(( ord - 40 ))
# Finally, map the new value back to a character.
fl=$(printf '%b' '\'${ord})
fi
echo "${fl}${foo:1}"

This works too...
FooBar=baz
echo ${FooBar^^${FooBar:0:1}}
=> Baz
FooBar=baz
echo ${FooBar^^${FooBar:1:1}}
=> bAz
FooBar=baz
echo ${FooBar^^${FooBar:2:2}}
=> baZ
And so on.
Sources:
Bash Manual: Shell Parameter Expansion
Full Bash Guide: Parameters
Bash Hacker's Wiki Parameter Expansion
Inroductions/Tutorials:
Cyberciti.biz: 8. Convert to upper to lower case or vice versa
Opensource.com: An introduction to parameter expansion in Bash

This one worked for me:
Searching for all *php file in the current directory , and replace the first character of each filename to capital letter:
e.g: test.php => Test.php
for f in *php ; do mv "$f" "$(\sed 's/.*/\u&/' <<< "$f")" ; done

Alternative and clean solution for both Linux and OSX, it can also be used with bash variables
python -c "print(\"abc\".capitalize())"
returns Abc

This is POSIX sh-compatible as far as I know.
upper_first.sh:
#!/bin/sh
printf "$1" | cut -c1 -z | tr -d '\0' | tr [:lower:] [:upper:]
printf "$1" | cut -c2-
cut -c1 -z ends the first string with \0 instead of \n. It gets removed with tr -d '\0'. It also works to omit the -z and use tr -d '\n' instead, but this breaks if the first character of the string is a newline.
Usage:
$ upper_first.sh foo
Foo
$
In a function:
#!/bin/sh
function upper_first ()
{
printf "$1" | cut -c1 -z | tr -d '\0' | tr [:lower:] [:upper:]
printf "$1" | cut -c2-
}
old="foo"
new="$(upper_first "$old")"
echo "$new"

Posix compliant and with less sub-processes:
v="foo[Bar]"
printf "%s" "${v%"${v#?}"}" | tr '[:lower:]' '[:upper:]' && printf "%s" "${v#?}"
==> Foo[Bar]

first-letter-to-lower () {
str=""
space=" "
for i in $#
do
if [ -z $(echo $i | grep "the\|of\|with" ) ]
then
str=$str"$(echo ${i:0:1} | tr '[A-Z]' '[a-z]')${i:1}$space"
else
str=$str${i}$space
fi
done
echo $str
}
first-letter-to-upper-xc () {
v-first-letter-to-upper | xclip -selection clipboard
}
first-letter-to-upper () {
str=""
space=" "
for i in $#
do
if [ -z $(echo $i | grep "the\|of\|with" ) ]
then
str=$str"$(echo ${i:0:1} | tr '[a-z]' '[A-Z]')${i:1}$space"
else
str=$str${i}$space
fi
done
echo $str
}
first-letter-to-lower-xc(){
v-first-letter-to-lower | xclip -selection clipboard
}

Not exactly what asked but quite helpful
declare -u foo #When the variable is assigned a value, all lower-case characters are converted to upper-case.
foo=bar
echo $foo
BAR
And the opposite
declare -l foo #When the variable is assigned a value, all upper-case characters are converted to lower-case.
foo=BAR
echo $foo
bar

What if the first character is not a letter (but a tab, a space, and a escaped double quote)? We'd better test it until we find a letter! So:
S=' \"ó foo bar\"'
N=0
until [[ ${S:$N:1} =~ [[:alpha:]] ]]; do N=$[$N+1]; done
#F=`echo ${S:$N:1} | tr [:lower:] [:upper:]`
#F=`echo ${S:$N:1} | sed -E -e 's/./\u&/'` #other option
F=`echo ${S:$N:1}
F=`echo ${F} #pure Bash solution to "upper"
echo "$F"${S:(($N+1))} #without garbage
echo '='${S:0:(($N))}"$F"${S:(($N+1))}'=' #garbage preserved
Foo bar
= \"Foo bar=

Related

How to cut variables which are beteween quotes from a string

I had problem with cut variables from string in " quotes. I have some scripts to write for my sys classes, I had a problem with a script in which I had to read input from the user in the form of (a="var1", b="var2")
I tried the code below
#!/bin/bash
read input
a=$($input | cut -d '"' -f3)
echo $a
it returns me a error "not found a command" on line 3 I tried to double brackets like
a=$(($input | cut -d '"' -f3)
but it's still wrong.
In a comment the OP gave a working answer (should post it as an answer):
#!/bin/bash
read input
a=$(echo $input | cut -d '"' -f2)
b=$(echo $input | cut -d '"' -f4)
echo sum: $(( a + b))
echo difference: $(( a - b))
This will work for user input that is exactly like a="8", b="5".
Never trust input.
You might want to add the check
if [[ ${input} =~ ^[a-z]+=\"[0-9]+\",\ [a-z]+=\"[0-9]+\"$ ]]; then
echo "Use your code"
else
echo "Incorrect input"
fi
And when you add a check, you might want to execute the input (after replacing the comma with a semicolon).
input='testa="8", testb="5"'
if [[ ${input} =~ ^[a-z]+=\"[0-9]+\",\ [a-z]+=\"[0-9]+\"$ ]];
then
eval $(tr "," ";" <<< ${input})
set | grep -E "^test[ab]="
else
echo no
fi
EDIT:
#PesaThe commented correctly about BASH_REMATCH:
When you use bash and a test on the input you can use
if [[ ${input} =~ ^[a-z]+=\"([0-9]+)\",\ [a-z]+=\"([0-9])+\"$ ]];
then
a="${BASH_REMATCH[1]}"
b="${BASH_REMATCH[2]}"
fi
To extract the digit 1 from a string "var1" you would use a Bash substring replacement most likely:
$ s="var1"
$ echo "${s//[^0-9]/}"
1
Or,
$ a="${s//[^0-9]/}"
$ echo "$a"
1
This works by replacing any non digits in a string with nothing. Which works in your example with a single number field in the string but may not be what you need if you have multiple number fields:
$ s2="1 and a 2 and 3"
$ echo "${s2//[^0-9]/}"
123
In this case, you would use sed or grep awk or a Bash regex to capture the individual number fields and keep them distinct:
$ echo "$s2" | grep -o -E '[[:digit:]]+'
1
2
3

Check if a string contains "-" and "]" at the same time

I have the next two regex in Bash:
1.^[-a-zA-Z0-9\,\.\;\:]*$
2.^[]a-zA-Z0-9\,\.\;\:]*$
The first matches when the string contains a "-" and the other values.
The second when contains a "]".
I put this values at the beginning of my regex because I can't scape them.
How I can get match the two values at the same time?
You can also place the - at the end of the bracket expression, since a range must be closed on both ends.
^[]a-zA-Z0-9,.;:-]*$
You don't have to escape any of the other characters, either. Colons, semicolons, and commas have no special meaning in any part of a regular expression, and while a period loses its special meaning inside a bracket expression.
Basically you can use this:
grep -E '^.*\-.*\[|\[.*\-.*$'
It matches either a - followed by zero or more arbitrary chars and a [ or a [ followed by zero or more chars and a -
However since you don't accept arbitrary chars, you need to change it to:
grep -E '^[a-zA-Z0-9,.;:]*\-[a-zA-Z0-9,.;:]*\[|\[[a-zA-Z0-9,.;:]*\-[a-zA-Z0-9,.;:]*$'
Maybe, this can help you
#!/bin/bash
while read p; do
echo $p | grep -E '\-.*\]|\].*\-' | grep "^[]a-zA-Z0-9,.;:-]*$"
done <$1
user-host:/tmp$ cat test
-i]string
]adfadfa-
string-
]string
str]ing
]123string
123string-
?????
++++++
user-host:/tmp$ ./test.sh test
-i]string
]adfadfa-
There are two questions in your post.
One is in the description:
How I can get match the two values at the same time?
That is an OR match, which could be done with a range that mix your two ranges:
pattern='^[]a-zA-Z0-9,.;:-]*$'
That will match a line that either contains one (or several) -…OR…]…OR any of the included characters. That would be all the lines (except ?????, ++++++ and as df gh) in the test script below.
Two is in the title:
… a string contains “-” and “]” at the same time
That is an AND match. The simplest (and slowest) way to do it is:
echo "$line" | grep '-' | grep ']' | grep '^[-a-zA-Z0-9,.;:]*$'
The first two calls to grep select only the lines that:
contain both (one or several) - and (one or several) ]
Test script:
#!/bin/bash
printlines(){
cat <<-\_test_lines_
asdfgh
asdfgh-
asdfgh]
as]df
as,df
as.df
as;df
as:df
as-df
as]]]df
as---df
asAS]]]DFdf
as123--456DF
as,.;:-df
as-dfg]h
as]dfg-h
a]s]d]f]g]h
a]s]d]f]g]h-
s-t-r-i-n-g]
as]df-gh
123]asdefgh
123asd-fgh-
?????
++++++
as df gh
_test_lines_
}
pattern='^[]a-zA-Z0-9,.;:-]*$'
printf '%s\n' "Testing the simple pattern of $pattern"
while read line; do
resultgrep="$( echo "$line" | grep "$pattern" )"
printf '%13s %-13s\n' "$line" "$resultgrep"
done < <(printlines)
echo "#############################################################"
echo
p1='-'; p2=']'; p3='^[]a-zA-Z0-9,.;:-]*$'
printf '%s\n' "Testing a 'grep AND' of '$p1', '$p2' and '$p3'."
while read line; do
resultgrep="$( echo "$line" | grep "$p1" | grep "$p2" | grep "$p3" )"
[[ $resultgrep ]] && printf '%13s %-13s\n' "$line" "$resultgrep"
done < <(printlines)
echo "#############################################################"
echo
printf '%s\n' "Testing an 'AWK AND' of '$p1', '$p2' and '$p3'."
while read line; do
resultawk="$( echo "$line" |
awk -v p1="$p1" -v p2="$p2" -v p3="$p3" '$0~p1 && $0~p2 && $0~p3' )"
[[ $resultawk ]] && printf '%13s %-13s\n' "$line" "$resultawk"
done < <(printlines)
echo "#############################################################"
echo
printf '%s\n' "Testing a 'bash AND' of '$p1', '$p2' and '$p3'."
while read line; do
rgrep="$( echo "$line" | grep "$p1" | grep "$p2" | grep "$p3" )"
[[ ( $line =~ $p1 ) && ( $line =~ $p2 ) && ( $line =~ $p3 ) ]]
rbash=${BASH_REMATCH[0]}
[[ $rbash ]] && printf '%13s %-13s %-13s\n' "$line" "$rgrep" "$rbash"
done < <(printlines)
echo "#############################################################"
echo

Convert to uppercase in shell

I am reading a character from keyboard and converting it to uppercase and then displaying the character again.
But the following code produces an error:
read a;
a=echo $a | tr 'a-z' 'A-Z'
echo $a
I also tried this:
read option;
eval $(awk -v option=$option '{print "a="toupper(option);}')
echo $a
If you want to store the result of a back in a, then you can do use command substitution:
read a;
a=$(echo $a | tr 'a-z' 'A-Z')
echo $a
This can be done natively in Bash as follows:
read a;
a="${a^^}"
echo "$a"
There is no need to invoke other commands like tr, because Bash can do this itself.
See also: Bash parameter expansion.
AWK is the right way to convert upper/lower case with full Unicode Support ;-)
echo "öäüßè" | awk 'BEGIN { getline; print toupper($0) }'
Use command substitution:
a=`echo $a | tr 'a-z' 'A-Z'`
Note the ticks ` around echo and tr.
using a bash script
printf "Type your Message Here: " read message
echo Upper Case: $message | tr [:lower:] [:upper:];
echo Lower Case: $message | tr [:upper:] [:lower:]
awk is the wrong way to go here, but here's one way it could be done:
a=$(awk 'BEGIN { getline; print toupper($0) }')
echo $a
Could not get
a=`echo $a | tr 'a-z' 'A-Z'`
to work, but
a=`echo $a | tr '[a-z]' '[A-Z]'`
did (note additional regex [] brackets.
Within a /usr/bin/sh script this worked as in
...
while getopts ":l:c:" option; do
case "$option"
in
l) L_OPT=`echo ${OPTARG}| tr '[a-z]' '[A-Z]'`
;;
c) C_OPT=`echo ${OPTARG} | tr '[a-z]' [A-Z]'`
;;
\?)
echo $USAGE
exit 1
;;
esac
done
...

First character of a variable in a shell script to uppercase?

I have a shell script that starts unit tests for modules. I need the name of the module in all lowercase and with the first character uppercase. So far I have been doing it like this:
#!/bin/sh -x
# z.B. getbrowser
strModuleToTest=$1
# g
strModuleToTestUppercaseFirstletter=${strModuleToTest:0:1}
# etbrowser
strModuleToTestUppercaseLastletters=${strModuleToTest:1}
# g -> G
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/a/A}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/b/B}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/c/C}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/d/D}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/e/E}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/f/F}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/g/G}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/h/H}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/i/I}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/j/J}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/k/K}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/l/L}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/m/M}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/n/N}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/o/O}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/p/P}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/q/Q}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/r/R}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/s/S}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/t/T}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/u/U}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/v/V}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/w/W}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/x/X}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/y/Y}"
strModuleToTestUppercaseFirstletter="${strModuleToTestUppercaseFirstletter/z/Z}"
# Getbrowser
strModuleToTestUppercase=$strModuleToTestUppercaseFirstletter""$strModuleToTestUppercaseLastletters
What would be an easier way to set $strModuleToTestUppercase? I tried
strModuleToTestUppercase="${strModuleToTest[#]^}"
or
strModuleToTestUppercasesed="sed 's/\<./\u&/g' $strModuleToTest"
but without success.
If:
s=somemodule
with bash v4+
echo ${s^}
This should work with a bit older bash versions (from Glenn):
echo $(tr a-z A-Z <<< ${s:0:1})${s:1}")
with zsh
echo ${(C)s}
with ash and coreutils
echo $(echo $s | cut -c1 | tr a-z A-Z)$(echo $s | cut -c2-)
with GNU sed
echo $s | sed 's/./\U&/'
with BSD sed
echo $s | sed '
h;
y/quvwxzdermatoglyphicsbfjkn/QUVWXZDERMATOGLYPHICSBFJKN/;
G;
s/\(.\)[^\n]*\n.\(.*\)/\1\2/;
'
with awk
echo $s | awk '{ print toupper(substr($0, 1, 1)) substr($0, 2) }'
with perl
echo $s | perl -nE 'say ucfirst'
with python
echo $s | python -c 'import sys; print sys.stdin.readline().rstrip().capitalize()'
with ruby
echo $s | ruby -e 'puts ARGF.read.capitalize'
Output in all cases
Somemodule
You could use
strModuleToTestUpper=`sed 's/\(.\)/\U\1/' <<< "$strModuleToTest"`
Explanation
\(.\) matches a single character
\U\1 replaces that character with an uppercase version
no /g means only the first match is processed.
Is perl ok?
$ x=foobar
$ x=$(echo "$x" | perl -pe 's/^(.)/uc($1)/e')
$ echo $x
Foobar

Redirect output to a bash array

I have a file containing the string
ipAddress=10.78.90.137;10.78.90.149
I'd like to place these two IP addresses in a bash array. To achieve that I tried the following:
n=$(grep -i ipaddress /opt/ipfile | cut -d'=' -f2 | tr ';' ' ')
This results in extracting the values alright but for some reason the size of the array is returned as 1 and I notice that both the values are identified as the first element in the array. That is
echo ${n[0]}
returns
10.78.90.137 10.78.90.149
How do I fix this?
Thanks for the help!
do you really need an array
bash
$ ipAddress="10.78.90.137;10.78.90.149"
$ IFS=";"
$ set -- $ipAddress
$ echo $1
10.78.90.137
$ echo $2
10.78.90.149
$ unset IFS
$ echo $# #this is "array"
if you want to put into array
$ a=( $# )
$ echo ${a[0]}
10.78.90.137
$ echo ${a[1]}
10.78.90.149
#OP, regarding your method: set your IFS to a space
$ IFS=" "
$ n=( $(grep -i ipaddress file | cut -d'=' -f2 | tr ';' ' ' | sed 's/"//g' ) )
$ echo ${n[1]}
10.78.90.149
$ echo ${n[0]}
10.78.90.137
$ unset IFS
Also, there is no need to use so many tools. you can just use awk, or simply the bash shell
#!/bin/bash
declare -a arr
while IFS="=" read -r caption addresses
do
case "$caption" in
ipAddress*)
addresses=${addresses//[\"]/}
arr=( ${arr[#]} ${addresses//;/ } )
esac
done < "file"
echo ${arr[#]}
output
$ more file
foo
bar
ipAddress="10.78.91.138;10.78.90.150;10.77.1.101"
foo1
ipAddress="10.78.90.137;10.78.90.149"
bar1
$./shell.sh
10.78.91.138 10.78.90.150 10.77.1.101 10.78.90.137 10.78.90.149
gawk
$ n=( $(gawk -F"=" '/ipAddress/{gsub(/\"/,"",$2);gsub(/;/," ",$2) ;printf $2" "}' file) )
$ echo ${n[#]}
10.78.91.138 10.78.90.150 10.77.1.101 10.78.90.137 10.78.90.149
This one works:
n=(`grep -i ipaddress filename | cut -d"=" -f2 | tr ';' ' '`)
EDIT: (improved, nestable version as per Dennis)
n=($(grep -i ipaddress filename | cut -d"=" -f2 | tr ';' ' '))
A variation on a theme:
$ line=$(grep -i ipaddress /opt/ipfile)
$ saveIFS="$IFS" # always save it and put it back to be safe
$ IFS="=;"
$ n=($line)
$ IFS="$saveIFS"
$ echo ${n[0]}
ipAddress
$ echo ${n[1]}
10.78.90.137
$ echo ${n[2]}
10.78.90.149
If the file has no other contents, you may not need the grep and you could read in the whole file.
$ saveIFS="$IFS"
$ IFS="=;"
$ n=$(</opt/ipfile)
$ IFS="$saveIFS"
A Perl solution:
n=($(perl -ne 's/ipAddress=(.*);/$1 / && print' filename))
which tests for and removes the unwanted characters in one operation.
You can do this by using IFS in bash.
First read the first line from file.
Seoncd convert that to an array with = as delimeter.
Third convert the value to an array with ; as delimeter.
Thats it !!!
#!/bin/bash
IFS='\n' read -r lstr < "a.txt"
IFS='=' read -r -a lstr_arr <<< $lstr
IFS=';' read -r -a ip_arr <<< ${lstr_arr[1]}
echo ${ip_arr[0]}
echo ${ip_arr[1]}

Resources