Cum pot tăia spațiul alb principal și final din fiecare linie a unei ieșiri?

Aș dori să șterg toate spațiile și filele din partea de sus și de pe fiecare linie dintr-o ieșire.

Există un instrument simplu ca trim Mi-aș putea introduce ieșirea în?

Exemplu de fișier:

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 

Comentarii

  • Pentru oricine caută aici o soluție pentru eliminarea liniilor noi, aceasta este o problemă diferită. Prin definiție, o linie nouă creează o nouă linie de text. Prin urmare, o linie de text nu poate conține o linie nouă. Întrebarea pe care doriți să o puneți este cum să eliminați o linie nouă de la începutul sau sfârșitul unui șir: stackoverflow.com/questions/369758 sau cum să eliminați golul linii sau linii care sunt doar spații albe: serverfault.com/questions/252921

Răspuns

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

sau mai scurt:

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

Ar tăia primul și spațiu final sau caractere tab 1 și, de asemenea, stoarce secvențe de file și spații într-un singur spațiu.

Acest lucru funcționează deoarece atunci când atribuiți ceva unuia dintre câmpurile , awk reconstruiește întregul record (așa cum este tipărit de print) prin alăturarea tuturor câmpurilor ($1, …, $NF) cu OFS (spațiu implicit).

1 (și, eventual, alt caracter gol depinde de localizare și de implementarea awk)

Comentarii

  • Punct și virgulă pe al doilea exemplu este de prisos. S-ar putea folosi: awk '{$1=$1}1'
  • @Brian, nu, ; este necesar în sintaxa standard awk
  • Interesant … Niciun punct și virgulă nu este acceptat de gawk, mawk și OS X ‘ s awk. (Cel puțin pentru versiunile mele (1.2, 4.1.1 și, respectiv, 20070501)
  • Singurul lucru care nu îmi place ‘ nu este că această abordare este pierdeți spațiile repetate din linie. De exemplu, echo -e 'foo \t bar' | awk '{$1=$1};1'
  • echo ' hello ' | xargs

Răspuns

Comanda poate fi condensată așa dacă folosiți GNU sed:

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

Exemplu

Aici este comanda de mai sus în acțiune.

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

Puteți utiliza hexdump pentru a confirma că comanda sed elimină corect caracterele dorite.

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

Clase de caractere

Puteți utiliza și nume de clase de caractere în loc să enumerați literalmente seturile astfel, [ \t]:

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

Exemplu

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

Majoritatea instrumentelor GNU care folosesc expre obișnuite ssions (regex) acceptă aceste clase (aici cu echivalentul lor în localizarea tipică C a unui sistem bazat pe ASCII (și numai acolo)).

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

aceste seturi în loc de literal pare întotdeauna o pierdere de spațiu, dar dacă sunteți îngrijorat de faptul că codul dvs. este portabil sau trebuie să aveți de-a face cu seturi de caractere alternative (gândiți-vă internațional), atunci veți dori probabil să folosiți numele claselor în loc .

Referințe

Comentarii

  • Rețineți că [[:space:]] nu este echivalent cu [ \t] caz general (unicode, etc). [[:space:]] va fi probabil mult mai lent (deoarece există mult mai multe tipuri de spații albe în unicode decât doar ' ' și '\t'). Același lucru pentru toate celelalte.
  • sed 's/^[ \t]*//' nu este portabil. În realitate POSIX necesită chiar și pentru a elimina o secvență de spațiu, backslash sau t caractere și că ‘ este ceea ce este GNU 51efbcd6df „>

funcționează și atunci cândPOSIXLY_CORRECTse află în mediul înconjurător.

  • Ce se întâmplă dacă vreau să decupez caractere newlines? ‘ \ n \ n text \ n \ n ‘
  • Îmi place soluția sed din cauza lipsei de alte efecte secundare ca în soluția awk. Prima variantă nu funcționează când am încercat-o în bash pe OSX jsut acum, dar versiunea clasei de caractere funcționează: sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
  • @EugeneBiryukov vezi comentariul meu despre postarea originală
  • Răspuns

    xargs fără argumente face asta.

    Exemplu:

    trimmed_string=$(echo "no_trimmed_string" | xargs) 

    Comentarii

    • De asemenea, aceasta contractează mai multe spații în o linie, care nu a fost solicitată la întrebarea
    • @roaima – adevărat, dar răspunsul acceptat stoarce și spații (ceea ce nu a fost solicitat în întrebare). Cred că adevărata problemă aici este că xargs nu va putea fi livrat dacă intrarea conține bare oblice și ghilimele simple.
    • @don_crissti care nu ‘ t înseamnă că răspunsul acceptat răspunde corect la întrebarea așa cum a fost pusă. Dar în acest caz aici nu a fost ‘ t marcat ca o avertizare, în timp ce în răspunsul acceptat a fost. Am ‘ sper că am evidențiat faptul că ‘ este relevant pentru un viitor cititor.
    • De asemenea, pauze pe ghilimele unice, ghilimele duble, caractere inversă. De asemenea, rulează una sau mai multe invocații echo. Unele implementări de ecou vor procesa, de asemenea, opțiuni și / sau backslash … Acest lucru funcționează și pentru intrarea cu o singură linie.

    Răspuns

    Așa cum sugerează Stéphane Chazelas în răspunsul acceptat, acum puteți crea un script /usr/local/bin/trim:

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

    și acordați acel fișier drepturi executabile:

    chmod +x /usr/local/bin/trim 

    Acum puteți transmite fiecare ieșire către trim de exemplu:

    cat file | trim 

    (pentru comentariile de mai jos: am folosit acest lucru înainte: while read i; do echo "$i"; done
    care funcționează și bine, dar este mai puțin performant)

    Comentarii

    • Noroc dacă fișierul dvs. este imens și / sau conține bare oblice.
    • @don_crissti: ați putea comenta ceva mai mult ?, ce soluție ar fi să fie mai potrivit pentru fișierele uriașe și cum aș putea modifica soluția dacă fișierul conținea bare oblice?
    • ‘ va trebui să utilizați while read -r line pentru a păstra bare oblice și chiar și atunci … . În ceea ce privește fișierele imense / viteza, într-adevăr, ați ales cea mai proastă soluție. Nu ‘ nu cred că există ‘ ceva mai rău acolo. Vedeți răspunsurile de pe De ce se folosește o buclă de shell pentru a procesa o practică nepotrivită a textului? , inclusiv comentariul meu la ultimul răspuns în care am adăugat un link la un indicator de viteză. Răspunsurile sed aici sunt perfect IMO și sunt mult mai bune decât read.
    • De asemenea, puteți adăuga un alias în / etc / profile (sau ~ / .bashrc sau ~ / .zshrc etc …) alias trim = ” awk ‘ { \ $ 1 = \ $ 1}; 1 ‘ ”
    • Nu este nevoie de bash, îl puteți face #! /usr/bin/awk -f {$1=$1};1. (feriți-vă de numele fișierelor care conțin = caractere)

    Răspuns

    Dacă stocați liniile ca variabile, puteți utiliza bash pentru a face treaba:

    eliminați spațiul alb principal dintr-un șir:

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

    eliminați spațiul alb dintr-un șir:

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

    eliminați tot spațiul alb dintr-un șir:

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

    Comentarii

    • Eliminarea întregului spațiu alb dintr-un șir nu este același lucru cu eliminarea atât a spațiilor de început, cât și a celei de final (ca în întrebare).
    • De departe cea mai bună soluție – necesită doar elemente integrate bash și fără furci de proces externe.
    • Frumos. Scripturile rulează MULȚI mai repede dacă nu ‘ nu trebuie să extragă programe externe (cum ar fi awk sau sed). Acest lucru funcționează și cu versiunile ” moderne ” (93u +) ale ksh.

    Răspuns

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

    Dacă citești o linie într-o variabilă shell, read face asta deja dacă nu este indicat altfel .

    Comentarii

    • +1 pentru read. Deci, dacă citiți în timp ce citiți, funcționează: cat file | while read i; do echo $i; done
    • @rubo cu excepția faptului că în exemplul dvs., variabila necitată este, de asemenea, reprocesată de shell. Utilizați echo "$i" pentru a vedea adevăratul efect al read

    Răspuns

    Pentru a elimina toate spațiile de la începutul și de la o linie dată datorită unui instrument „cu conductă”, pot identifica 3 diferite moduri care nu sunt complet echivalente. Aceste diferențe se referă la spațiile dintre cuvintele liniei de intrare. În funcție de b așteptat comportament, vei face alegerea ta.

    Exemple

    Pentru a explica diferențele, să luăm în considerare această linie de intrare fictivă:

    " \t A \tB\tC \t " 

    tr

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

    tr este într-adevăr o comandă simplă. În acest caz, șterge orice spațiu sau caracter de tabelare.

    awk

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

    awk șterge spațiile de conducere și de coadă și stoarce într-un singur spațiu fiecare spațiu dintre cuvinte.

    sed

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

    În acest caz, sed șterge spațiile de direcție și coadă fără a atinge spații între cuvinte.

    Observație:

    În cazul unui cuvânt pe linie, tr face treaba.

    Comentarii

    • Niciunul dintre aceste elemente nu urmărește / conduce linii noi, deși
    • +1 pentru o listă de soluții cu ieșirea lor (uneori neașteptată).
    • @ user61382 acest lucru este destul de târziu, dar vedeți comentariul meu la postarea originală.
    • @highmaintenance: utilizați [:space:], în loc de [: blank:], pentru comanda tr, cum ar fi: ... | tr -d [:space:], pentru a elimina și liniile noi. (vezi: man tr)

    Răspuns

    sed este un instrument excelent pentru asta:

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

    Puteți să-l utilizați pentru cazul dvs. fie în canal, fie în text, de ex.

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

    sau acționând pe acesta „inline” dacă sed este cel GNU:

    sed -i "s/..." file 

    dar schimbarea sursei în acest fel este „periculoasă”, deoarece poate fi nerecuperabilă atunci când nu funcționează corect (sau chiar și atunci când funcționează!), deci faceți mai întâi copie de rezervă (sau utilizați -i.bak care are și avantajul de a fi portabil pentru unele BSD sed s)!

    Răspuns

    Un răspuns pe care îl puteți înțelege dintr-o privire:

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

    Bonus: înlocuiți str.strip([chars]) cu caractere arbitrare pentru a tăia sau utiliza .lstrip() sau .rstrip() după cum este necesar.

    Ca rubo77 „sa nswer , salvați ca script /usr/local/bin/trim și dați permisiunile cu chmod +x.

    Răspuns

    Dacă șirul pe care încercăm să-l tăiem este scurt și continuu / contigu, îl puteți trece pur și simplu ca parametru la orice funcție bash:

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

    Răspuns

    Am scris această funcție shell folosind awk

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

    BEGIN{ RS="^$" }:
    la început înainte de a începe analiza setează înregistrarea
    separator la none adică tratează întreaga intrare ca
    o singură înregistrare

    gsub(this,that):
    înlocuiește această regexp cu acel șir

    /^[\n\t ]*|[\n\t ]*$/:
    din acel șir captează orice spațiu înainte de linie nouă și clasă de file
    sau postează spațiu de linie nouă și clasă de file și le înlocuiește cu
    șir gol

    print;exit: apoi tipăriți și ieșiți

    "$1":
    și treceți primul argument al funcției către fiți proces de awk

    cum să utilizați:
    copiați codul de mai sus, lipiți în shell, apoi introduceți pentru a defini
    funcția.
    atunci puteți utiliza awkcliptor ca o comandă cu primul argument ca fișier de intrare

    utilizare eșantion:

    echo " ggggg " > a_file awkcliptor a_file 

    ieșire:

    ggggg 

    sau

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

    ieșire:

    ggggg 

    Comentarii

    • Puteți explica diferența doar awk '{$1=$1};1'?

    Răspuns

    Pentru cei dintre noi fără suficient spațiu în creier pentru a ne aminti sintaxa sed obscură, inversați șirul , tăiați primul câmp cu un delimitator de spațiu și inversați-l din nou.

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

    Comentarii

    • Acest lucru funcționează numai dacă nu există mai mult de un spațiu care conduce fiecare linie și nu mai mult de un cuvânt în orice linie.

    Răspuns

    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: înlocuiți str.strip([chars]) cu caractere arbitrare pentru a tăia sau utiliza sau .rstrip() după cum este necesar.

    Răspuns

    comanda de traducere ar funcționa

    cat file | tr -d [:blank:] 

    Comentarii

    • Această comandă nu este corectă deoarece elimină Toate spațiile din fișier, nu doar spațiul alb principal / final.
    • @BrianRedbeard Aveți dreptate. Acesta este încă un răspuns util pentru un șir monolitic, fără spații.

    Răspuns

    pentru exemplu bash:

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

    utilizare:

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

    rezultat:

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

    Comentarii

    • Răspunsul awk '{$1=$1};1' a fost dat cu mult timp în urmă. Ideea de a crea un alias din acesta a fost sugerată într-un comentariu aproape la fel de demult. Da, aveți voie să luați comentariile altcuiva și să le transformați într-un răspuns. Dar, dacă o faceți, ar trebui să acordați credit persoanelor care au postat ideea în fața dvs. Și aceasta este o extensie atât de banală a răspunsului acceptat, încât nu merită să te deranjezi.
    • Ideea era să faci un alias. ‘ nu am mai văzut răspunsul anterior.
    • și al doilea lucru din stivă: ” Vă mulțumim pentru feedback! Voturile exprimate de cei cu o reputație mai mică de 15 sunt înregistrate, dar nu modifică scorul afișat public. ”

    Lasă un răspuns

    Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *