Hvordan trimmer jeg ledende og etterfølgende mellomrom fra hver linje med noe output?

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 eller t tegn, og at ‘ er hva GNU sed gjør også når POSIXLY_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 enn read.
  • 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 av read

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 kommandoen tr, 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. »

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *