Ik heb een temp
-bestand met wat kleine letters en hoofdletters.
Invoer
Inhoud van mijn temp
bestand:
hi Jigar GANDHI jiga
Ik wil alle boven naar beneden converteren .
Commando
Ik probeerde het volgende commando:
sed -e "s/[A-Z]/[a-z]/g" temp
maar kreeg verkeerde uitvoer.
Uitvoer
Ik wil het als:
hi jigar gandhi jiga
Wat moet in het vervangende gedeelte zitten van argument voor sed
?
Reacties
- Zie ook Hoe UTF-8 txt-bestanden te converteren naar hoofdletters in bash?
Answer
Als uw invoer alleen ASCII-tekens bevat, kunt u tr
gebruiken zoals:
of (minder gemakkelijk te onthouden en IMO; maar niet beperkt tot Latijnse ASCII-letters, hoewel in sommige implementaties inclusief GNU tr
, nog steeds beperkt tot tekens van één byte, dus in UTF-8-landinstellingen, nog steeds beperkt tot ASCII-letters):
tr "[:upper:]" "[:lower:]" < input
als je sed
moet gebruiken:
sed "s/.*/\L&/g" < input
(hier uitgaande van de GNU-implementatie).
Met POSIX sed
, zou je “alle transliteraties moeten specificeren en dan kun je kiezen welke letters die u wilt converteren:
sed "y/AǼBCΓDEFGH.../aǽbcγdefgh.../" < input
Met awk
:
awk "{print tolower($0)}" < input
Reacties
- Merk op dat
\L
een GNU-extensie is. -
\L
werkt tot nu toe goed voor mij. En licht het punt toe dat je probeert om GNU extensie - @JigarGandhi te maken.
sed
is een Unix-commando. Verschillende systemen hebben verschillende varianten met verschillend gedrag en d functionaliteit. Gelukkig is er tegenwoordig ‘ een standaard die hier het meest aan voldoet, zodat u kunt rekenen op een minimum aan functies die iedereen gemeenschappelijk heeft.\L
is er niet bij en werd geïntroduceerd door GNUsed
(komt overeen met dezelfde operator in standaardex
/vi
) en is over het algemeen niet beschikbaar in andere implementaties. - Merk op dat sommige
tr
implementaties zoals GNUtr
niet ‘ werken niet correct in multi-byte landinstellingen (de meeste zijn tegenwoordig, probeerecho STÉPHANE | tr '[:upper:]' '[:lower:]'
bijvoorbeeld). Op GNU-systemen geeft u misschien de voorkeur aan desed
variant ofawk
‘ stolower()
. - Kleine correctie:
sed 's/.*/\L&/g' < input
. De\1
verwijzing naar de overeenkomende deelstring zal ‘ niet werken, tenzij je de deelstring specificeert met haakjes zoals Wurtle doet in zijn. Het ‘ is echter iets schoner om&
te gebruiken om de hele overeenkomst weer te geven, zoals weergegeven
Answer
Met vim is het supereenvoudig:
$ vim filename gg0guGZZ
Opent het bestand gg
gaat naar de eerste regel, 0
, eerste kolom. Met guG
, verlaagt het hoofdlettergebruik van alle tekens tot de onderkant van het bestand. ZZ
slaat op en sluit af.
Het zou zo ongeveer alles moeten verwerken wat je erin gooit; het “ll negeer getallen, het” zal niet ASCII behandelen.
Als je het tegenovergestelde wilt doen, verander dan de kleine letters in hoofdletters, verwissel de u
uit voor een U
: gg0gUGZZ
en je bent klaar.
Reacties
- Lol ” super simpel ”
- dit doet duidelijk niet ‘ t goed schalen voor veel bestanden
- @CoreyGoldberg
vim file1 file2 fileetc
en dan iets als:bufdo gg0guG:w<CR>
zou waarschijnlijk werken voor een willekeurig aantal bestanden. Heb dat echter niet getest! - @TankorSmash dat nog steeds niet ‘ opschaalt naar een groot aantal bestanden
Antwoord
Zelf vind ik dd
hiervoor leuk.
<<\IN LC_ALL=C 2<>/dev/null \ dd conv=lcase hi Jigar GANDHI jiga IN
… krijgt …
hi jigar ghandi jiga
De LC_ALL=C
is om alle multibytes in invoer te beschermen – hoewel multibyte-hoofdletters niet worden geconverteerd. Hetzelfde geldt voor (GNU) tr
– beide apps zijn gevoelig voor invoerverminking in elke niet-C-landinstelling. iconv
kan met beide worden gecombineerd voor een uitgebreide oplossing.
De 2>/dev/null
omleiding verwijdert het standaardstatusrapport van dd
“- en zijn status. Zonder dd
zou volgen op voltooiing van een taak zoals de bovenstaande met afdrukinformatie zoals hoeveel bytes werden verwerkt enz.
Opmerkingen
- Deze oplossing is veel sneller dan
tr
bij het verwerken van grote bestanden, bedankt!
Antwoord
Je kunt ook Perl 5 gebruiken:
perl -pe "$_=lc" temp
De optie -p
vertelt perl om de gespecificeerde uitdrukking één keer uit te voeren voor elke invoerregel, waarbij het resultaat wordt afgedrukt, dwz de laatste waarde van $_
. -e
geeft aan dat de programma zal het volgende argument zijn, in tegenstelling tot een bestand dat het script bevat. lc
converteert naar kleine letters. Zonder argument werkt het op $_
. En $_=
slaat dat opnieuw op zodat het wordt afgedrukt.
Een variatie daarvan zou zijn
perl -ne "print lc" temp
-n
is als -p
behalve dat $_
uiteindelijk niet wordt afgedrukt. Dus in plaats van op te slaan in die variabele, voeg ik een expliciete printinstructie toe.
Een voordeel van Perl in tegenstelling tot sed is dat je geen GNU-extensies nodig hebt. Er zijn projecten die compatibel moeten zijn met niet-GNU-omgevingen, maar die ook al een afhankelijkheid van Perl hebben. In vergelijking met tr
, kan het zijn dat Perl lc
gemakkelijker locaalbewust gemaakt kan worden. Zie de perllocale
man-pagina voor details.
Antwoord
Je moet vastleggen het overeenkomende patroon en gebruik het dan in de vervanging met een modifier:
sed "s/\([A-Z]\)/\L\1/g" temp
De \(...\)
“vangt” de met overeenkomende tekst, de eerste opname gaat naar \1
, de volgende naar \2
, enz. De nummering is volgens de openingshaakjes in het geval van geneste opnames.
De \L
converteert het vastgelegde patroon naar kleine letters, er is ook \U
voor hoofdletters .
Reacties
- je hoeft dit niet te doen – het hele patroon zit altijd in
&
- Klopt, maar dan had ik de kans gemist om het vastleggen van overeenkomsten uit te leggen 🙂
Antwoord
Naast het antwoord van MvG, zou je ook Perl 6 kunnen gebruiken:
perl6 -pe .=lc temp
Hier is $ _ impliciet, en je hebt geen enkele aanhalingstekens nodig om het te beschermen tegen uitbreiding door de shell ($ _ is een speciale Bash-parameter; zie: https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html )