Hoe kan ik de voorloop- en volgspaties van elke regel van een bepaalde uitvoer bijsnijden?

Ik zou graag alle voorloop- en volgspaties en tabs van elke regel in een uitvoer willen verwijderen.

Is er een eenvoudige tool zoals trim Ik zou mijn output naar kunnen pipen?

Voorbeeldbestand:

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 

Reacties

  • Voor iedereen die hier op zoek is naar een oplossing om nieuwe regels te verwijderen, is dat een ander probleem. Per definitie creëert een nieuwe regel een nieuwe regel tekst. Daarom kan een regel tekst geen nieuwe regel bevatten. De vraag die u wilt stellen, is hoe u een nieuwe regel verwijdert aan het begin of einde van een tekenreeks: stackoverflow.com/questions/369758 , of hoe u lege regels of regels die gewoon witruimte zijn: serverfault.com/questions/252921

Antwoord

awk "{$1=$1;print}" 

of korter:

awk "{$1=$1};1" 

spatie of tabtekens 1 en ook knijp reeksen tabs en spaties in een enkele spatie.

Dat werkt, want als je iets toewijst aan een van de velden , awk bouwt het hele record opnieuw op (zoals afgedrukt door print) door alle velden samen te voegen ($1, …, $NF) met OFS (standaard spatie).

1 (en mogelijk een ander leeg teken s afhankelijk van de landinstelling en de awk implementatie)

Opmerkingen

  • Puntkomma op tweede voorbeeld is overbodig. Kan gebruiken: awk '{$1=$1}1'
  • @Brian, nee, de ; is vereist in de standaard awk-syntaxis
  • Interessant … Geen puntkomma wordt ondersteund door gawk, mawk en OS X ‘ s awk. (Althans voor mijn versies (respectievelijk 1.2, 4.1.1 en 20070501).
  • Het enige dat ik ‘ niet leuk vind aan deze aanpak, is dat je verlies herhalende spaties binnen de regel. Bijvoorbeeld echo -e 'foo \t bar' | awk '{$1=$1};1'
  • echo ' hello ' | xargs

Answer

Het commando kan zo worden gecomprimeerd als je “GNU gebruikt sed:

$ sed "s/^[ \t]*//;s/[ \t]*$//" < file 

Voorbeeld

Hier is het bovenstaande commando in actie.

$ echo -e " \t blahblah \t " | sed "s/^[ \t]*//;s/[ \t]*$//" blahblah 

U kunt hexdump gebruiken om te bevestigen dat de opdracht sed de gewenste tekens correct verwijdert.

$ echo -e " \t blahblah \t " | sed "s/^[ \t]*//;s/[ \t]*$//" | hexdump -C 00000000 62 6c 61 68 62 6c 61 68 0a |blahblah.| 00000009 

Tekenklassen

U kunt ook tekenklassenamen gebruiken in plaats van de sets letterlijk op deze manier op te sommen, [ \t]:

$ sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//" < file 

Voorbeeld

$ echo -e " \t blahblah \t " | sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//" 

De meeste GNU-tools die gebruik maken van reguliere expre ssions (regex) ondersteunen deze klassen (hier met hun equivalent in de typische C-locale van een ASCII-gebaseerd systeem (en alleen daar)).

 [[: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 

deze in plaats van letterlijke sets lijken altijd een verspilling van ruimte, maar als je je zorgen maakt over het feit dat je code draagbaar is, of te maken hebt met alternatieve tekensets (denk internationaal), dan wil je waarschijnlijk de klassennamen gebruiken .

Referenties

Opmerkingen

  • Merk op dat [[:space:]] niet gelijk is aan [ \t] in de algemeen geval (unicode, enz.). [[:space:]] zal waarschijnlijk veel langzamer zijn (aangezien er veel meer typen witruimten in Unicode zijn dan alleen ' ' en '\t'). Hetzelfde geldt voor alle andere.
  • sed 's/^[ \t]*//' is niet draagbaar. Eigenlijk vereist POSIX zelfs dat om een reeks spatie, backslash of t tekens te verwijderen, en dat ‘ s wat GNU sed doet het ook wanneer POSIXLY_CORRECT zich in de omgeving bevindt.
  • Wat moet ik doen als ik tekens voor nieuwe regels wil inkorten? ‘ \ n \ n text \ n \ n ‘
  • Ik hou van de sed-oplossing vanwege het gebrek aan andere bijwerkingen zoals in de awk-oplossing. De eerste variant werkt niet toen ik het nu in bash op OSX jsut probeerde, maar de character class-versie werkt wel: sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
  • @EugeneBiryukov zie mijn commentaar op het originele bericht

Antwoord

xargs zonder argumenten doen dat.

Voorbeeld:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

Reacties

  • Hierdoor worden ook meerdere spaties binnen een regel, die niet werd gevraagd in de vraag
  • @roaima – waar, maar het geaccepteerde antwoord drukt ook spaties samen (wat niet werd gevraagd in de vraag). Ik denk dat het echte probleem hier is dat xargs niet zal worden weergegeven als de invoer backslashes en enkele aanhalingstekens bevat.
  • @don_crissti dat niet ‘ betekent echter dat het geaccepteerde antwoord de gestelde vraag correct beantwoordt. Maar in dit geval werd het hier niet ‘ t gemarkeerd als voorbehoud, terwijl het in het geaccepteerde antwoord was. Ik ‘ heb hopelijk het feit benadrukt voor het geval het ‘ s relevant is voor een toekomstige lezer.
  • Het is ook pauzes op enkele aanhalingstekens, dubbele aanhalingstekens, backslash-tekens. Het voert ook een of meer echo aanroepen uit. Sommige echo-implementaties zullen ook opties en / of backslashes verwerken … Dat werkt ook alleen voor invoer van één regel.

Answer

Zoals voorgesteld door Stéphane Chazelas in het geaccepteerde antwoord, kun je nu
een script maken /usr/local/bin/trim:

#!/bin/bash awk "{$1=$1};1" 

en geef dat bestand uitvoerbare rechten:

chmod +x /usr/local/bin/trim 

Nu kunt u elke uitvoer doorgeven aan trim bijvoorbeeld:

cat file | trim 

(voor de opmerkingen hieronder: ik heb dit eerder gebruikt: while read i; do echo "$i"; done
wat ook prima werkt, maar minder performant is)

Opmerkingen

  • Veel succes als je bestand enorm is en / of backslashes bevat.
  • @don_crissti: kun je wat meer commentaar geven ?, welke oplossing zou beter geschikt zijn voor grote bestanden, en hoe kan ik mijn oplossing aanpassen als het bestand backslashes bevat?
  • U ‘ zult while read -r line moeten gebruiken om backslashes te behouden en zelfs dan … . Wat betreft enorme bestanden / snelheid, heb je echt de slechtste oplossing gekozen. Ik denk niet dat ‘ er ‘ iets ergers is. Zie de antwoorden op Waarom wordt een shell-loop gebruikt om tekst te verwerken als een slechte gewoonte? inclusief mijn opmerking over het laatste antwoord waar ik een link naar een snelheidsbenchmark heb toegevoegd. De sed antwoorden hier zijn prima IMO en veel beter dan read.
  • Je kunt ook een alias toevoegen aan / etc / profile (of je ~ / .bashrc of ~ / .zshrc etc …) alias trim = ” awk ‘ { \ $ 1 = \ $ 1}; 1 ‘ ”
  • bash, je kunt het #! /usr/bin/awk -f {$1=$1};1 maken. (pas echter op voor bestandsnamen die = tekens bevatten)

Antwoord

Als u regels opslaat als variabelen, kunt u bash gebruiken om het werk te doen:

verwijder voorloopspaties uit een string:

shopt -s extglob echo ${text##+([[:space:]])} 

verwijder spaties aan het einde van een string:

shopt -s extglob echo ${text%%+([[:space:]])} 

verwijder alle witruimte uit een string:

echo ${text//[[:space:]]} 

Opmerkingen

  • Het verwijderen van alle witruimte uit een string is niet hetzelfde als het verwijderen van zowel voorloop- als volgspaties (zoals in kwestie).
  • Veruit de beste oplossing – het vereist alleen ingebouwde bash en geen externe procesvorken.
  • Mooi. Scripts werken VEEL sneller als ze ‘ geen externe programmas hoeven binnen te halen (zoals awk of sed). Dit werkt ook met ” modern ” (93u +) versies van ksh.

Answer

sed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//" 

Als u “een regel in een shell-variabele leest, read doet dat al tenzij anders aangegeven .

Reacties

  • +1 voor read. Dus als je tijdens het lezen doorspoelt, werkt het: cat file | while read i; do echo $i; done
  • @rubo behalve dat in uw voorbeeld wordt de niet-aangehaalde variabele ook opnieuw verwerkt door de shell. Gebruik echo "$i" om het ware effect te zien van de read

Answer

Om alle voorloop- en volgspaties van een bepaalde regel te verwijderen dankzij een “doorgesluisde” tool, kan ik 3 verschillende manieren die niet volledig equivalent zijn. Deze verschillen betreffen de spaties tussen woorden van de invoerregel. Afhankelijk van de verwachte b Hoe dan ook, u zult uw keuze maken.

Voorbeelden

Laten we, om de verschillen uit te leggen, deze dummy-invoerregel bekijken:

" \t A \tB\tC \t " 

tr

$ echo -e " \t A \tB\tC \t " | tr -d "[:blank:]" ABC 

tr is echt een eenvoudig commando. In dit geval wordt elke spatie of tabulatieteken verwijderd.

awk

$ echo -e " \t A \tB\tC \t " | awk "{$1=$1};1" A B C 

awk verwijdert voorloop- en staartspaties en drukt elke spatie tussen woorden in een enkele spatie.

sed

$ echo -e " \t A \tB\tC \t " | sed "s/^[ \t]*//;s/[ \t]*$//" A B C 

In dit geval sed verwijdert begin- en eindspaties zonder spaties tussen woorden aan te raken.

Opmerking:

In het geval van één woord per regel, tr doet het werk.

Opmerkingen

  • Niets van dit trimt echter achterliggende / leidende nieuwe regels
  • +1 voor een lijst met oplossingen met hun (soms onverwachte) uitvoer.
  • @ user61382 dit is nogal laat, maar zie mijn opmerking over het oorspronkelijke bericht.
  • @highmaintenance: gebruik [:space:], in plaats van [: blank:], voor het commando tr, zoals: ... | tr -d [:space:], om ook nieuwe regels te verwijderen. (zie: man tr)

Antwoord

sed is een geweldig hulpmiddel daarvoor:

 # substitute ("s/") sed "s/^[[:blank:]]*//; # parts of lines that start ("^") with a space/tab s/[[:blank:]]*$//" # or end ("$") with a space/tab # with nothing (/) 

Je kunt het voor jouw geval gebruiken door een piping in de tekst te gebruiken, bijvoorbeeld

<file sed -e "s/^[[... 

of door ernaar te handelen “inline” als uw sed de GNU-versie is:

sed -i "s/..." file 

maar het op deze manier wijzigen van de bron is “gevaarlijk”, aangezien het onherstelbaar kan zijn als het niet “goed werkt (of zelfs als dat wel het geval is!), dus maak eerst een back-up (of gebruik -i.bak wat ook het voordeel heeft dat het overdraagbaar is naar een BSD sed s)!

Antwoord

Een antwoord dat u in één oogopslag begrijpt:

#!/usr/bin/env python3 import sys for line in sys.stdin: print(line.strip()) 

Bonus: vervang str.strip([chars]) met willekeurige tekens om te trimmen of gebruik .lstrip() of .rstrip() indien nodig.

Zoals rubo77 “sa nswer , sla op als script /usr/local/bin/trim en geef rechten met chmod +x.

Antwoord

Als de string die men probeert te trimmen kort en continu / aaneengesloten is, kan men deze gewoon als parameter doorgeven naar elke bash-functie:

 trim(){ echo $@ } a=" some random string " echo ">>`trim $a`<<" Output >>some random string<< 

Answer

Ik schreef deze shell-functie met awk

awkcliptor(){ awk -e "BEGIN{ RS="^$" } {gsub(/^[\n\t ]*|[\n\t ]*$/,"");print ;exit}" "$1" ; } 

BEGIN{ RS="^$" }:
in het begin voor het parseren zet record
scheidingsteken op geen dwz behandel de hele invoer als
een enkel record

gsub(this,that):
vervang deze regexp door die string

/^[\n\t ]*|[\n\t ]*$/:
van die string vang een pre newline space en tab class op
of post newline space en tab class en vervang ze door
lege string

print;exit: print en sluit af

"$1":
en geef het eerste argument van de functie door aan be
process by awk

hoe te gebruiken:
kopieer bovenstaande code, plak in shell, en voer dan in om
definieren de functie.
dan kun je awkcliptor gebruiken als een commando met het eerste argument als het invoerbestand.

voorbeeldgebruik:

echo " ggggg " > a_file awkcliptor a_file 

output:

ggggg 

of

echo -e "\n ggggg \n\n "|awkcliptor 

output:

ggggg 

Reacties

  • Kunt u het verschil uitleggen met alleen awk '{$1=$1};1'?

Answer

Voor degenen onder ons die niet genoeg ruimte in de hersenen hebben om obscure sed-syntaxis te onthouden, keert u de tekenreeks gewoon om , knip het eerste veld af met een scheidingsteken van de spatie en draai het weer terug.

cat file | rev | cut -d" " -f1 | rev 

Reacties

  • Dit werkt alleen als er niet meer dan één spatie voor elke regel staat en niet meer dan één woord op een regel.

Answer

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: vervang str.strip([chars]) door willekeurige tekens om in te korten of gebruik of .rstrip() indien nodig.

Antwoord

commando vertalen zou werken

cat file | tr -d [:blank:] 

Reacties

  • Dit commando is niet correct aangezien het verwijdert alle spaties uit het bestand, niet alleen voorloop / volg spaties.
  • @BrianRedbeard Je hebt gelijk. Dit is nog steeds een handig antwoord voor een monolithische string, zonder spaties.

Antwoord

voor bash-voorbeeld:

alias trim="awk "{\$1=\$1};1"" 

gebruik:

echo -e " hello\t\tkitty " | trim | hexdump -C 

resultaat:

00000000 68 65 6c 6c 6f 20 6b 69 74 74 79 0a |hello kitty.| 0000000c 

Reacties

  • Het awk '{$1=$1};1' antwoord is lang geleden gegeven. Het idee om er een alias van te maken, werd bijna net zo lang geleden in een opmerking gesuggereerd. Ja, u mag de opmerking van iemand anders opnemen en er een antwoord van maken. Maar als u dat doet, moet u de mensen die het idee voor u hebben gepost, erkennen. En dit is zon triviale uitbreiding van het geaccepteerde antwoord dat het de moeite niet echt waard is.
  • Het idee was om een alias te maken. Ik heb dat antwoord niet eerder ‘ gezien.
  • en tweede ding van stapel: ” Bedankt voor de feedback! Stemmen die worden uitgebracht door mensen met een reputatie van minder dan 15 worden opgenomen, maar verander de publiekelijk weergegeven postscore niet. ”

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *