Odpowiedzi:
Istnieją różne sposoby:
$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all
$ echo "$a" | awk '{print tolower($0)}'
hi all
Mogą wystąpić problemy z przenośnością z następującymi przykładami:
$ echo "${a,,}"
hi all
$ echo "$a" | sed -e 's/\(.*\)/\L\1/'
hi all
# this also works:
$ sed -e 's/\(.*\)/\L\1/' <<< "$a"
hi all
$ echo "$a" | perl -ne 'print lc'
hi all
lc(){
case "$1" in
[A-Z])
n=$(printf "%d" "'$1")
n=$((n+32))
printf \\$(printf "%o" "$n")
;;
*)
printf "%s" "$1"
;;
esac
}
word="I Love Bash"
for((i=0;i<${#word};i++))
do
ch="${word:$i:1}"
lc "$ch"
done
Uwaga: YMMV w tym przypadku. Nie działa dla mnie (GNU bash w wersji 4.2.46 i 4.0.33 (i to samo zachowanie 2.05b.0, ale nocasematch nie jest zaimplementowany)) nawet przy użyciu shopt -u nocasematch;
. Wyłączenie tej opcji nocasematch powoduje, że [["fooBaR" == "FOObar"]] pasuje do OK ALE dziwnie wewnątrz skrzynki [bz] są niepoprawnie dopasowane do [AZ] Bash jest zdezorientowany podwójnie ujemnym („niepokojącym nocasematch”)! :-)
word="Hi All"
podobnie jak w innych przykładach, to ha
nie hi all
. Działa tylko w przypadku wielkich liter i pomija już małe litery.
tr
i awk
przykłady są określone w standardzie POSIX.
tr '[:upper:]' '[:lower:]'
użyje bieżących ustawień narodowych do określenia odpowiedników wielkich / małych liter, więc będzie działać z ustawieniami narodowymi, które używają liter ze znakami diakrytycznymi.
b="$(echo $a | tr '[A-Z]' '[a-z]')"
W Bash 4:
Na małe litery
$ string="A FEW WORDS"
$ echo "${string,}"
a FEW WORDS
$ echo "${string,,}"
a few words
$ echo "${string,,[AEIUO]}"
a FeW WoRDS
$ string="A Few Words"
$ declare -l string
$ string=$string; echo "$string"
a few words
Do wielkich liter
$ string="a few words"
$ echo "${string^}"
A few words
$ echo "${string^^}"
A FEW WORDS
$ echo "${string^^[aeiou]}"
A fEw wOrds
$ string="A Few Words"
$ declare -u string
$ string=$string; echo "$string"
A FEW WORDS
Przełącz (nieudokumentowane, ale opcjonalnie konfigurowalne w czasie kompilacji)
$ string="A Few Words"
$ echo "${string~~}"
a fEW wORDS
$ string="A FEW WORDS"
$ echo "${string~}"
a FEW WORDS
$ string="a few words"
$ echo "${string~}"
A few words
Wielkie litery (nieudokumentowane, ale opcjonalnie konfigurowalne w czasie kompilacji)
$ string="a few words"
$ declare -c string
$ string=$string
$ echo "$string"
A few words
Tytuł sprawy:
$ string="a few words"
$ string=($string)
$ string="${string[@]^}"
$ echo "$string"
A Few Words
$ declare -c string
$ string=(a few words)
$ echo "${string[@]}"
A Few Words
$ string="a FeW WOrdS"
$ string=${string,,}
$ string=${string~}
$ echo "$string"
A few words
Aby wyłączyć declare
atrybut, użyj +
. Na przykład declare +c string
. Wpływa to na kolejne przypisania, a nie na bieżącą wartość.
Te declare
opcje zmienić atrybut zmiennej, ale nie zawartość. Ponowne przypisania w moich przykładach aktualizują zawartość, aby pokazać zmiany.
Edytować:
Dodano „przełącz pierwszy znak po słowie” ( ${var~}
) zgodnie z sugestią ghostdog74 .
Edycja: Poprawiono zachowanie tyldy, aby pasowało do Bash 4.3.
string="łódź"; echo ${string~~}
„ŁÓDŹ”, ale echo ${string^^}
zwróci „łóDź”. Nawet w LC_ALL=pl_PL.utf-8
. To używa bash 4.2.24.
en_US.UTF-8
. To błąd i zgłosiłem go.
echo "$string" | tr '[:lower:]' '[:upper:]'
. Prawdopodobnie wykaże tę samą awarię. Tak więc problem przynajmniej częściowo nie dotyczy Basha.
echo "Hi All" | tr "[:upper:]" "[:lower:]"
tr
nie działa dla mnie dla znaków spoza ACII. Mam prawidłowy zestaw ustawień regionalnych i wygenerowane pliki ustawień narodowych. Masz pojęcie, co mogę zrobić źle?
[:upper:]
potrzebny
a="$(tr [A-Z] [a-z] <<< "$a")"
{ print tolower($0) }
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
a="$(tr [A-Z] [a-z] <<< "$a")"
wygląda dla mnie najłatwiej. Nadal jestem początkującym ...
sed
rozwiązanie; Pracowałem w środowisku, które z jakiegoś powodu nie ma, tr
ale jeszcze nie znalazłem systemu bez sed
, a poza tym dużo czasu chcę to zrobić. Właśnie zrobiłem coś innego, sed
więc mogę połączyć polecenia razem w jedną (długą) instrukcję.
tr [A-Z] [a-z] A
powłoce może wykonać rozszerzenie nazwy pliku, jeśli istnieją nazwy plików składające się z jednej litery lub ustawiono nullgob . tr "[A-Z]" "[a-z]" A
będzie się zachowywał poprawnie.
sed
tr [A-Z] [a-z]
jest nieprawidłowy w prawie wszystkich lokalizacjach. na przykład w en-US
ustawieniach regionalnych A-Z
jest faktycznie interwał AaBbCcDdEeFfGgHh...XxYyZ
.
Wiem, że to stary post, ale podałem tę odpowiedź dla innej witryny, więc pomyślałem, że opublikuję ją tutaj:
GÓRNA -> dolna : użyj Pythona:
b=`echo "print '$a'.lower()" | python`
Lub Ruby:
b=`echo "print '$a'.downcase" | ruby`
Lub Perl (prawdopodobnie mój ulubiony):
b=`perl -e "print lc('$a');"`
Lub PHP:
b=`php -r "print strtolower('$a');"`
Lub Awk:
b=`echo "$a" | awk '{ print tolower($1) }'`
Lub Sed:
b=`echo "$a" | sed 's/./\L&/g'`
Lub Bash 4:
b=${a,,}
Lub NodeJS, jeśli go masz (i jesteś trochę szalony ...):
b=`echo "console.log('$a'.toLowerCase());" | node`
Możesz także użyć dd
(ale nie chciałbym!):
b=`echo "$a" | dd conv=lcase 2> /dev/null`
niższe -> GÓRNE :
użyj python:
b=`echo "print '$a'.upper()" | python`
Lub Ruby:
b=`echo "print '$a'.upcase" | ruby`
Lub Perl (prawdopodobnie mój ulubiony):
b=`perl -e "print uc('$a');"`
Lub PHP:
b=`php -r "print strtoupper('$a');"`
Lub Awk:
b=`echo "$a" | awk '{ print toupper($1) }'`
Lub Sed:
b=`echo "$a" | sed 's/./\U&/g'`
Lub Bash 4:
b=${a^^}
Lub NodeJS, jeśli go masz (i jesteś trochę szalony ...):
b=`echo "console.log('$a'.toUpperCase());" | node`
Możesz także użyć dd
(ale nie chciałbym!):
b=`echo "$a" | dd conv=ucase 2> /dev/null`
Także kiedy mówisz „shell”, zakładam, że masz na myśli, bash
ale jeśli możesz użyć, zsh
jest to tak proste jak
b=$a:l
dla małych liter i
b=$a:u
dla wielkich liter.
a
zawiera pojedynczy cytat, masz nie tylko zepsute zachowanie, ale poważny problem z bezpieczeństwem.
W Zsh:
echo $a:u
Uwielbiam Zsh!
echo ${(C)a} #Upcase the first char only
Pre Bash 4.0
Bash Opuść wielkość liter ciągu i przypisz do zmiennej
VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]')
echo "$VARIABLE"
echo
i rur: użyj$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Dla standardowej powłoki (bez bashism) używającej tylko wbudowanych poleceń:
uppers=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lowers=abcdefghijklmnopqrstuvwxyz
lc(){ #usage: lc "SOME STRING" -> "some string"
i=0
while ([ $i -lt ${#1} ]) do
CUR=${1:$i:1}
case $uppers in
*$CUR*)CUR=${uppers%$CUR*};OUTPUT="${OUTPUT}${lowers:${#CUR}:1}";;
*)OUTPUT="${OUTPUT}$CUR";;
esac
i=$((i+1))
done
echo "${OUTPUT}"
}
I dla wielkich liter:
uc(){ #usage: uc "some string" -> "SOME STRING"
i=0
while ([ $i -lt ${#1} ]) do
CUR=${1:$i:1}
case $lowers in
*$CUR*)CUR=${lowers%$CUR*};OUTPUT="${OUTPUT}${uppers:${#CUR}:1}";;
*)OUTPUT="${OUTPUT}$CUR";;
esac
i=$((i+1))
done
echo "${OUTPUT}"
}
${var:1:1}
są Bashizmem.
Możesz tego spróbować
s="Hello World!"
echo $s # Hello World!
a=${s,,}
echo $a # hello world!
b=${s^^}
echo $b # HELLO WORLD!
ref: http://wiki.workassis.com/shell-script-convert-text-to-lowercase-and-uppercase/
Chciałbym podziękować za polecenie, którym chcę się podzielić, ale prawda jest taka, że uzyskałem je na własny użytek ze strony http://commandlinefu.com . Ma tę zaletę, że jeśli cd
przejdziesz do dowolnego katalogu w swoim własnym folderze domowym, to znaczy zmieni wszystkie pliki i foldery na małe litery rekurencyjnie, używaj ostrożnie. Jest to doskonała poprawka do wiersza poleceń i szczególnie przydatna w przypadku wielu albumów przechowywanych na dysku.
find . -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
Możesz podać katalog zamiast kropki (.) Po znalezieniu, który oznacza bieżący katalog lub pełną ścieżkę.
Mam nadzieję, że to rozwiązanie okaże się użyteczne. Jedyną rzeczą, której nie robi to polecenie, jest zastąpienie spacji znakami podkreślenia - no cóż, może innym razem.
prename
od perl
: dpkg -S "$(readlink -e /usr/bin/rename)"
dajeperl: /usr/bin/prename
Wiele odpowiedzi za pomocą zewnętrznych programów, które tak naprawdę nie są używane Bash
.
Jeśli wiesz, że będziesz mieć dostępną wersję Bash4, powinieneś po prostu użyć ${VAR,,}
notacji (jest to łatwe i fajne). W przypadku wersji Bash przed 4 (na moim komputerze Mac nadal jest używana wersja Bash 3.2). Użyłem poprawionej wersji odpowiedzi @ ghostdog74, aby stworzyć bardziej przenośną wersję.
Możesz zadzwonić lowercase 'my STRING'
i uzyskać małą wersję. Czytam komentarze na temat ustawiania wyniku na var, ale to nie jest tak naprawdę przenośne Bash
, ponieważ nie możemy zwrócić ciągów. Drukowanie to najlepsze rozwiązanie. Łatwy do uchwycenia za pomocą czegoś takiego var="$(lowercase $str)"
.
Jak to działa
Działa to poprzez uzyskanie reprezentacji liczb całkowitych ASCII każdego znaku za pomocą, printf
a następnie adding 32
if upper-to->lower
lub subtracting 32
if lower-to->upper
. Następnie użyj printf
ponownie, aby przekonwertować liczbę z powrotem na znak. Od 'A' -to-> 'a'
mamy różnicę 32 znaków.
Za pomocą printf
wyjaśnienia:
$ printf "%d\n" "'a"
97
$ printf "%d\n" "'A"
65
97 - 65 = 32
A to jest wersja robocza z przykładami.
Zwróć uwagę na komentarze w kodzie, ponieważ wyjaśniają wiele rzeczy:
#!/bin/bash
# lowerupper.sh
# Prints the lowercase version of a char
lowercaseChar(){
case "$1" in
[A-Z])
n=$(printf "%d" "'$1")
n=$((n+32))
printf \\$(printf "%o" "$n")
;;
*)
printf "%s" "$1"
;;
esac
}
# Prints the lowercase version of a sequence of strings
lowercase() {
word="$@"
for((i=0;i<${#word};i++)); do
ch="${word:$i:1}"
lowercaseChar "$ch"
done
}
# Prints the uppercase version of a char
uppercaseChar(){
case "$1" in
[a-z])
n=$(printf "%d" "'$1")
n=$((n-32))
printf \\$(printf "%o" "$n")
;;
*)
printf "%s" "$1"
;;
esac
}
# Prints the uppercase version of a sequence of strings
uppercase() {
word="$@"
for((i=0;i<${#word};i++)); do
ch="${word:$i:1}"
uppercaseChar "$ch"
done
}
# The functions will not add a new line, so use echo or
# append it if you want a new line after printing
# Printing stuff directly
lowercase "I AM the Walrus!"$'\n'
uppercase "I AM the Walrus!"$'\n'
echo "----------"
# Printing a var
str="A StRing WITH mixed sTUFF!"
lowercase "$str"$'\n'
uppercase "$str"$'\n'
echo "----------"
# Not quoting the var should also work,
# since we use "$@" inside the functions
lowercase $str$'\n'
uppercase $str$'\n'
echo "----------"
# Assigning to a var
myLowerVar="$(lowercase $str)"
myUpperVar="$(uppercase $str)"
echo "myLowerVar: $myLowerVar"
echo "myUpperVar: $myUpperVar"
echo "----------"
# You can even do stuff like
if [[ 'option 2' = "$(lowercase 'OPTION 2')" ]]; then
echo "Fine! All the same!"
else
echo "Ops! Not the same!"
fi
exit 0
A wyniki po uruchomieniu tego:
$ ./lowerupper.sh
i am the walrus!
I AM THE WALRUS!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
myLowerVar: a string with mixed stuff!
myUpperVar: A STRING WITH MIXED STUFF!
----------
Fine! All the same!
Powinno to jednak działać tylko w przypadku znaków ASCII .
Dla mnie jest w porządku, ponieważ wiem, że przekażę mu tylko znaki ASCII.
Używam tego na przykład do niektórych opcji CLI bez rozróżniania wielkości liter.
Konwersja jest wykonywana tylko dla alfabetów. Więc to powinno działać dobrze.
Koncentruję się na konwersji alfabetów między az z wielkich na małe litery. Wszelkie inne postacie powinny być po prostu wydrukowane w stdout, ponieważ jest ...
Konwertuje cały tekst w ścieżce / na / plik / nazwę pliku z zakresu az na AZ
Do konwersji małych i wielkich liter
cat path/to/file/filename | tr 'a-z' 'A-Z'
Do konwersji z wielkich na małe litery
cat path/to/file/filename | tr 'A-Z' 'a-z'
Na przykład,
Nazwa pliku:
my name is xyz
zostanie przekonwertowany na:
MY NAME IS XYZ
Przykład 2:
echo "my name is 123 karthik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 KARTHIK
Przykład 3:
echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK
Jeśli używasz v4, jest to włączone . Jeśli nie, oto proste, szeroko stosowane rozwiązanie. Inne odpowiedzi (i komentarze) w tym wątku były bardzo pomocne w tworzeniu poniższego kodu.
# Like echo, but converts to lowercase
echolcase () {
tr [:upper:] [:lower:] <<< "${*}"
}
# Takes one arg by reference (var name) and makes it lowercase
lcase () {
eval "${1}"=\'$(echo ${!1//\'/"'\''"} | tr [:upper:] [:lower:] )\'
}
Uwagi:
a="Hi All"
a następnie: lcase a
zrobi to samo, co:a=$( echolcase "Hi All" )
${!1//\'/"'\''"}
zamiast ${!1}
pozwala na to, aby działało nawet wtedy, gdy ciąg zawiera cudzysłowy.W przypadku wersji Bash wcześniejszych niż 4.0 ta wersja powinna być najszybsza (ponieważ nie rozwidla / nie wykonuje żadnych poleceń):
function string.monolithic.tolower
{
local __word=$1
local __len=${#__word}
local __char
local __octal
local __decimal
local __result
for (( i=0; i<__len; i++ ))
do
__char=${__word:$i:1}
case "$__char" in
[A-Z] )
printf -v __decimal '%d' "'$__char"
printf -v __octal '%03o' $(( $__decimal ^ 0x20 ))
printf -v __char \\$__octal
;;
esac
__result+="$__char"
done
REPLY="$__result"
}
Odpowiedź technozaura też miała potencjał, choć dla mnie działała poprawnie.
Pomimo wieku tego pytania i podobnego do odpowiedzi udzielonej przez technozaura . Trudno mi było znaleźć rozwiązanie, które byłoby przenośne na większości platform (których używam), a także na starszych wersjach bash. Byłem również sfrustrowany tablicami, funkcjami i wykorzystaniem wydruków, echa i plików tymczasowych do wyszukiwania trywialnych zmiennych. Działa to dla mnie bardzo dobrze. Moje główne środowiska testowe to:
- GNU bash, wersja 4.1.2 (1) -release (x86_64-redhat-linux-gnu)
- GNU bash, wersja 3.2.57 (1) -release (sparc-sun-solaris2.10)
lcs="abcdefghijklmnopqrstuvwxyz"
ucs="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
input="Change Me To All Capitals"
for (( i=0; i<"${#input}"; i++ )) ; do :
for (( j=0; j<"${#lcs}"; j++ )) ; do :
if [[ "${input:$i:1}" == "${lcs:$j:1}" ]] ; then
input="${input/${input:$i:1}/${ucs:$j:1}}"
fi
done
done
Prosty styl C dla pętli do iteracji po łańcuchach. W poniższej linii, jeśli nie widziałeś czegoś takiego wcześniej, tutaj się tego nauczyłem . W tym przypadku wiersz sprawdza, czy znak $ {input: $ i: 1} (małe litery) istnieje w danych wejściowych, a jeśli tak, to zastępuje go danym znakiem $ {ucs: $ j: 1} (wielkie litery) i przechowuje go z powrotem do wejścia.
input="${input/${input:$i:1}/${ucs:$j:1}}"
Jest to znacznie szybsza odmiana podejścia JaredTS486, który wykorzystuje natywne możliwości Bash (w tym wersje Bash <4.0) do optymalizacji swojego podejścia.
Zmierzyłem czas 1000 iteracji tego podejścia dla małego ciągu (25 znaków) i większego ciągu (445 znaków), zarówno dla konwersji małych jak i wielkich liter. Ponieważ ciągi testowe są przeważnie pisane małymi literami, konwersje na małe litery są na ogół szybsze niż na wielkie.
Porównałem swoje podejście z kilkoma innymi odpowiedziami na tej stronie, które są kompatybilne z Bash 3.2. Moje podejście jest znacznie bardziej wydajne niż większość podejść tutaj udokumentowanych i jest nawet szybsze niż tr
w kilku przypadkach.
Oto wyniki synchronizacji dla 1000 iteracji po 25 znaków:
tr
małe litery; 3,81s dla wielkich literWyniki czasowe dla 1000 iteracji 445 znaków (składających się z wiersza „Robin” Wittera Bynnera):
tr
małe litery; 4s dla wielkich literRozwiązanie:
#!/bin/bash
set -e
set -u
declare LCS="abcdefghijklmnopqrstuvwxyz"
declare UCS="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
function lcase()
{
local TARGET="${1-}"
local UCHAR=''
local UOFFSET=''
while [[ "${TARGET}" =~ ([A-Z]) ]]
do
UCHAR="${BASH_REMATCH[1]}"
UOFFSET="${UCS%%${UCHAR}*}"
TARGET="${TARGET//${UCHAR}/${LCS:${#UOFFSET}:1}}"
done
echo -n "${TARGET}"
}
function ucase()
{
local TARGET="${1-}"
local LCHAR=''
local LOFFSET=''
while [[ "${TARGET}" =~ ([a-z]) ]]
do
LCHAR="${BASH_REMATCH[1]}"
LOFFSET="${LCS%%${LCHAR}*}"
TARGET="${TARGET//${LCHAR}/${UCS:${#LOFFSET}:1}}"
done
echo -n "${TARGET}"
}
Podejście jest proste: podczas gdy w ciągu wejściowym znajdują się pozostałe wielkie litery, znajdź następną i zamień wszystkie wystąpienia tej litery na jej małą literę. Powtarzaj, aż wszystkie wielkie litery zostaną zastąpione.
Niektóre cechy wydajności mojego rozwiązania:
UCS
i LCS
może być uzupełniony o dodatkowe postacie