Jeg vil fjerne alle ledende og etterfølgende mellomrom og faner fra hver linje i en utdata.
Er det et enkelt verktøy som trim
Jeg kunne pipe utdataene mine i?
Eksempel på fil:
test space at back test space at front TAB at end TAB at front sequence of some space in the middle some empty lines with differing TABS and spaces: test space at both ends
Kommentarer
- For alle som leter etter en løsning for å fjerne nye linjer, er det et annet problem. Per definisjon oppretter en ny linje en ny tekstlinje. Derfor kan en tekstlinje ikke inneholde en ny linje. Spørsmålet du vil stille er hvordan du fjerner en ny linje fra begynnelsen eller slutten av en streng: stackoverflow.com/questions/369758 , eller hvordan du fjerner tomt linjer eller linjer som bare er mellomrom: serverfault.com/questions/252921
Svar
awk "{$1=$1;print}"
eller kortere:
awk "{$1=$1};1"
Ville trimme førende og bakrom eller tabulatortegn 1 og også klemmer sekvenser av faner og mellomrom i et enkelt mellomrom.
Det fungerer fordi når du tildeler noe til et av feltene , bygger awk
hele posten (som trykt av print
) ved å slå sammen alle feltene ($1
, …, $NF
) med OFS
(mellomrom som standard).
1 (og muligens annet tomt tegn s avhengig av lokalitet og awk
implementering)
Kommentarer
- Semikolon på andre eksempel er overflødig. Kan bruke:
awk '{$1=$1}1'
- @Brian, nei,
;
kreves i standard awk-syntaksen - Interessant … Ingen semikolon støttes av gawk, mawk og OS X ‘ s awk. (I det minste for versjonene mine (henholdsvis 1.2, 4.1.1 og 20070501)
- Det eneste jeg ikke ‘ liker med denne tilnærmingen er at du miste gjentatte mellomrom innenfor linjen. For eksempel
echo -e 'foo \t bar' | awk '{$1=$1};1'
-
echo ' hello ' | xargs
Svar
Kommandoen kan kondenseres slik hvis du bruker GNU sed
:
$ sed "s/^[ \t]*//;s/[ \t]*$//" < file
Eksempel
Her er kommandoen ovenfor i aksjon.
$ echo -e " \t blahblah \t " | sed "s/^[ \t]*//;s/[ \t]*$//" blahblah
Du kan bruke hexdump
for å bekrefte at sed
kommandoen fjerner de ønskede tegnene riktig.
$ echo -e " \t blahblah \t " | sed "s/^[ \t]*//;s/[ \t]*$//" | hexdump -C 00000000 62 6c 61 68 62 6c 61 68 0a |blahblah.| 00000009
Tegnklasser
Du kan også bruke tegnklassenavn i stedet for bokstavelig å oppføre settene slik, [ \t]
:
$ sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//" < file
Eksempel
$ echo -e " \t blahblah \t " | sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//"
De fleste av GNU-verktøyene som bruker vanlig utl. ssions (regex) støtter disse klassene (her med deres tilsvarende i den typiske C-lokaliteten til et ASCII-basert system (og bare der)).
[[:alnum:]] - [A-Za-z0-9] Alphanumeric characters [[:alpha:]] - [A-Za-z] Alphabetic characters [[:blank:]] - [ \t] Space or tab characters only [[:cntrl:]] - [\x00-\x1F\x7F] Control characters [[:digit:]] - [0-9] Numeric characters [[:graph:]] - [!-~] Printable and visible characters [[:lower:]] - [a-z] Lower-case alphabetic characters [[:print:]] - [ -~] Printable (non-Control) characters [[:punct:]] - [!-/:-@[-`{-~] Punctuation characters [[:space:]] - [ \t\v\f\n\r] All whitespace chars [[:upper:]] - [A-Z] Upper-case alphabetic characters [[:xdigit:]] - [0-9a-fA-F] Hexadecimal digit characters
Bruk disse i stedet for bokstavelige sett virker alltid som sløsing med plass, men hvis du er opptatt av at koden din er bærbar, eller du trenger å håndtere alternative tegnsett (tenk internasjonalt), vil du sannsynligvis bruke klassenavnene i stedet .
Referanser
Kommentarer
- Merk at
[[:space:]]
ikke tilsvarer[ \t]
i generelt tilfelle (unicode, etc).[[:space:]]
vil sannsynligvis være mye tregere (ettersom det er mange flere typer hvite mellomrom i unicode enn bare' '
og'\t'
). Samme for alle de andre. -
sed 's/^[ \t]*//'
er ikke bærbar. POSIX krever til og med at for å fjerne en sekvens med mellomrom, tilbakeslag ellert
tegn, og at ‘ er hva GNUsed
gjør også nårPOSIXLY_CORRECT
er i miljøet. - Hva om jeg vil trimme nye linjer? ‘ \ n \ n tekst \ n \ n ‘
- Jeg liker sed-løsningen på grunn av mangel på andre bivirkninger som i awk-løsningen. Den første variasjonen fungerer ikke da jeg prøvde den i bash på OSX jsut nå, men karakterklasseversjonen fungerer:
sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
- @EugeneBiryukov se min kommentar til det opprinnelige innlegget
Svar
xargs uten argumenter gjør det.
Eksempel:
trimmed_string=$(echo "no_trimmed_string" | xargs)
Kommentarer
- Dette trekker også sammen flere mellomrom innen en linje, som ikke ble bedt om i spørsmålet
- @roaima – sant, men det aksepterte svaret klemmer også mellomrom (som ikke ble bedt om i spørsmålet). Jeg tror det virkelige problemet her er at
xargs
ikke vil levere hvis innspillet inneholder tilbakeslag og enkelt anførselstegn. - @don_crissti som ikke ‘ t betyr at det aksepterte svaret svarer riktig på spørsmålet som det blir stilt. Men i dette tilfellet ble det ikke ‘ t flagget som en advarsel, mens det i det aksepterte svaret var det. Jeg ‘ har forhåpentligvis fremhevet faktum i tilfelle det ‘ er relevant for en fremtidig leser.
- Det har også bryter på enkelt anførselstegn, doble anførselstegn, tilbakeslagstegn. Den kjører også en eller flere
echo
påkallinger. Noen ekkoimplementeringer vil også behandle alternativer og / eller tilbakeslag … Det fungerer også bare for en-linjers inngang.
Svar
Som foreslått av Stéphane Chazelas i det aksepterte svaret, kan du nå
lage et skript /usr/local/bin/trim
:
#!/bin/bash awk "{$1=$1};1"
og gi den filen kjørbare rettigheter:
chmod +x /usr/local/bin/trim
Nå kan du sende alle utdata til trim
for eksempel:
cat file | trim
(for kommentarene nedenfor: jeg brukte dette før: while read i; do echo "$i"; done
som også fungerer bra, men som er mindre performant)
Kommentarer
- Lykke til hvis filen din er enorm og / eller inneholder tilbakeslag.
- @don_crissti: kan du kommentere litt mer ?, hvilken løsning ville være bedre egnet for store filer, og hvordan kan jeg endre løsningen hvis filen inneholder tilbakeslag?
- Du ‘ du må bruke
while read -r line
for å bevare tilbakeslag og selv da … . Når det gjelder store filer / hastighet, valgte du virkelig den verste løsningen. Jeg tror ikke ‘ der ‘ er noe verre der ute. Se svarene på Hvorfor bruker jeg en shell-løkke til å behandle tekst dårlig praksis? inkludert kommentaren til det siste svaret der jeg la til en lenke til en hastighetsindeks.sed
svarene her er helt fine IMO og langt bedre ennread
. - Du kan også legge til et alias i / etc / profile (eller ~ / .bashrc eller ~ / .zshrc etc …) alias trim = » awk ‘ { \ $ 1 = \ $ 1}; 1 ‘ »
- Ingen behov for
bash
, du kan lage det#! /usr/bin/awk -f
{$1=$1};1
. (pass på filnavn som inneholder=
tegn skjønt)
Svar
Hvis du lagrer linjer som variabler, kan du bruke bash til å gjøre jobben:
fjern ledende mellomrom fra en streng:
shopt -s extglob echo ${text##+([[:space:]])}
fjern etterfølgende mellomrom fra en streng:
shopt -s extglob echo ${text%%+([[:space:]])}
fjern alt mellomrom fra en streng:
echo ${text//[[:space:]]}
Kommentarer
- Å fjerne all mellomrom fra en streng er ikke det samme som å fjerne både ledende og etterfølgende mellomrom (som det er snakk om).
- Den aller beste løsningen – den krever bare bash-innebygde og ingen eksterne prosessgafler.
- Hyggelig. Skript kjører MYE raskere hvis de ikke ‘ ikke trenger å hente inn eksterne programmer (for eksempel awk eller sed). Dette fungerer også med » moderne » (93u +) versjoner av ksh.
Svar
sed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//"
Hvis du leser en linje inn i en skallvariabel, read
gjør det allerede med mindre annet er instruert .
Kommentarer
- +1 for
read
. Så hvis du piper til mens du leser, fungerer det:cat file | while read i; do echo $i; done
- @rubo bortsett fra at i eksemplet ditt blir den ikke-siterte variabelen også bearbeidet av skallet. Bruk
echo "$i"
for å se den virkelige effekten avread
Svar
For å fjerne alle ledende og etterfølgende mellomrom fra en gitt linje takket være et «piped» -verktøy, kan jeg identifisere 3 forskjellige måter som ikke er helt likeverdige. Disse forskjellene gjelder mellomrom mellom ordene på inngangslinjen. Avhengig av forventet b ehaviour, du vil gjøre ditt valg.
Eksempler
For å forklare forskjellene, la oss vurdere denne dummy-inngangslinjen:
" \t A \tB\tC \t "
tr
$ echo -e " \t A \tB\tC \t " | tr -d "[:blank:]" ABC
tr
er virkelig en enkel kommando. I dette tilfellet sletter det hvilket som helst mellomrom eller tabellkarakter.
awk
$ echo -e " \t A \tB\tC \t " | awk "{$1=$1};1" A B C
awk
sletter ledende og haler mellomrom og klemmer til et mellomrom mellom hvert mellomrom mellom ord.
sed
$ echo -e " \t A \tB\tC \t " | sed "s/^[ \t]*//;s/[ \t]*$//" A B C
I dette tilfellet sed
sletter ledende og haler mellomrom uten å berøre mellomrom mellom ord.
Bemerkning:
Når det gjelder ett ord per linje, gjør tr
jobben.
Kommentarer
- Ingen av dette trimmer etterfølgende / ledende nye linjer skjønt
- +1 for en liste over løsninger med deres (noen ganger uventede) utdata.
- @ user61382 dette er ganske sent, men se kommentaren til det opprinnelige innlegget.
- @highmaintenance: bruk
[:space:]
, i stedet for [: blank:], for kommandoentr
, som:... | tr -d [:space:]
, for å fjerne nye linjer også. (se:man tr
)
Svar
sed er en flott verktøy for det:
# substitute ("s/") sed "s/^[[:blank:]]*//; # parts of lines that start ("^") with a space/tab s/[[:blank:]]*$//" # or end ("$") with a space/tab # with nothing (/)
Du kan bruke det for ditt tilfelle, enten rør i teksten, f.eks.
<file sed -e "s/^[[...
eller ved å handle på den «inline» hvis sed
er GNU-en:
sed -i "s/..." file
men å endre kilden på denne måten er «farlig», da det kan være uopprettelig når det ikke fungerer riktig (eller til og med når det gjør det!), så ta sikkerhetskopi først (eller bruk -i.bak
som også har fordelen av å være bærbar til noen BSD sed
s)!
Svar
Et svar du raskt kan forstå:
#!/usr/bin/env python3 import sys for line in sys.stdin: print(line.strip())
Bonus: erstatt str.strip([chars])
med vilkårlige tegn for å trimme eller bruke .lstrip()
eller .rstrip()
etter behov.
Liker rubo77 «sa nswer , lagre som skript /usr/local/bin/trim
og gi tillatelser med chmod +x
.
Svar
Hvis strengen man prøver å trimme er kort og kontinuerlig / sammenhengende, kan man ganske enkelt sende den som en parameter til hvilken som helst bash-funksjon:
trim(){ echo $@ } a=" some random string " echo ">>`trim $a`<<" Output >>some random string<<
Svar
Jeg skrev denne skallfunksjonen ved hjelp av awk
awkcliptor(){ awk -e "BEGIN{ RS="^$" } {gsub(/^[\n\t ]*|[\n\t ]*$/,"");print ;exit}" "$1" ; }
BEGIN{ RS="^$" }
:
i begynnelsen før du begynner å analysere sett post og separator til ingen dvs. behandle hele inngangen som en enkelt post
gsub(this,that)
:
erstatte denne regexp med den strengen
/^[\n\t ]*|[\n\t ]*$/
:
av den strengen fanger et hvilket som helst før-linjeplass og faneklasse
eller legg ut ny-linjeplass og kategoriklasse og erstatt dem med
tom streng
print;exit
: skriv ut og avslutt
"$1"
:
og send det første argumentet til funksjonen til være
prosess med awk
hvordan du bruker:
kopiere over kode, lime inn i skallet, og skriv deretter inn for å definere funksjonen.
så kan du bruke awkcliptor som en kommando med første argument som inndatafilen
eksempelbruk:
echo " ggggg " > a_file awkcliptor a_file
utgang:
ggggg
eller
echo -e "\n ggggg \n\n "|awkcliptor
utgang:
ggggg
Kommentarer
- Kan du forklare forskjellen til bare
awk '{$1=$1};1'
?
Svar
For de av oss uten nok plass i hjernen til å huske uklar sed syntaks, er det bare å snu strengen , kutt det første feltet med en avgrensning av mellomrom, og snu det tilbake igjen.
cat file | rev | cut -d" " -f1 | rev
Kommentarer
- Dette fungerer bare hvis det ikke er mer enn ett mellomrom som fører hver linje og ikke mer enn ett ord i en linje.
Svar
trimpy () { python3 -c "import sys for line in sys.stdin: print(line.strip())" } trimsed () { gsed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//" } trimzsh () { local out="$(</dev/stdin)" [[ "$out" =~ "^\s*(.*\S)\s*$" ]] && out="$match[1]" || out="" print -nr -- "$out" } # example usage echo " hi " | trimpy
Bonus: erstatt str.strip([chars])
med vilkårlige tegn for å trimme eller bruk eller .rstrip()
etter behov.
Svar
Oversett kommando ville fungert
cat file | tr -d [:blank:]
Kommentarer
- Denne kommandoen er ikke riktig da den fjerner alle mellomrom fra filen, ikke bare ledende / etterfølgende mellomrom.
- @BrianRedbeard Du har rett. Dette er fortsatt et nyttig svar for en monolitisk streng uten mellomrom.
Svar
for bash-eksempel:
alias trim="awk "{\$1=\$1};1""
bruk:
echo -e " hello\t\tkitty " | trim | hexdump -C
resultat:
00000000 68 65 6c 6c 6f 20 6b 69 74 74 79 0a |hello kitty.| 0000000c
Kommentarer
-
awk '{$1=$1};1'
svaret ble gitt for lenge siden. Ideen om å lage et alias ut av det ble foreslått i en kommentar nesten like lenge siden. Ja, du har lov til å ta en andres kommentar og gjøre den om til et svar. Men hvis du gjør det, bør du gi æren til folkene som la ut ideen før deg. Og dette er en så triviell utvidelse av det aksepterte svaret at det egentlig ikke er verdt bryet. - Ideen var å lage alias. Jeg så ikke ‘ det svaret før.
- og andre ting fra stabel: » Takk for tilbakemeldingen! Stemmer avgitt av personer med mindre enn 15 omdømme registreres, men endrer ikke poengsummen som vises offentlig. »