Jeg vil gerne fjerne alle ledende og bageste mellemrum og faner fra hver linje i en output.
Er der et simpelt værktøj som trim
Jeg kunne pibe min output til?
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
- Til alle, der søger her efter en løsning til at fjerne nye linjer, er det et andet problem. Per definition opretter en ny linje en ny tekstlinje. Derfor kan en tekstlinje ikke indeholde en ny linje. Det spørgsmål, du vil stille, er, hvordan du fjerner en ny linje fra begyndelsen eller slutningen af en streng: stackoverflow.com/questions/369758 , eller hvordan du fjerner tomt linjer eller linjer, der kun er mellemrum: serverfault.com/questions/252921
Svar
awk "{$1=$1;print}"
eller kortere:
awk "{$1=$1};1"
Vil trimme førende og efterfølgende mellemrum eller tabulatortegn 1 og også klem sekvenser af faner og mellemrum i et enkelt mellemrum.
Det fungerer, fordi når du tildeler noget til et af felterne , genopbygger awk
hele posten (som udskrevet af print
) ved sammenføjning af alle felter ($1
, …, $NF
) med OFS
(mellemrum som standard).
1 (og muligvis andet tomt tegn s afhængigt af lokalitet og awk
implementering)
Kommentarer
- Semikolon til andet eksempel er overflødigt. Kunne bruge:
awk '{$1=$1}1'
- @Brian, nej,
;
kræves i standard awk-syntaksen - Interessant … Intet semikolon understøttes af gawk, mawk og OS X ‘ s awk. (I det mindste for mine versioner (henholdsvis 1.2, 4.1.1 og 20070501)
- Det eneste, jeg ikke ‘ kan lide ved denne tilgang er, at du mister gentagne mellemrum inden for linjen. F.eks.
echo -e 'foo \t bar' | awk '{$1=$1};1'
-
echo ' hello ' | xargs
Svar
Kommandoen kan kondenseres som hvis du “bruger GNU sed
:
$ sed "s/^[ \t]*//;s/[ \t]*$//" < file
Eksempel
Her er ovenstående kommando i aktion.
$ echo -e " \t blahblah \t " | sed "s/^[ \t]*//;s/[ \t]*$//" blahblah
Du kan bruge hexdump
til at bekræfte, at kommandoen sed
fjerner de ønskede tegn korrekt.
$ 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å bruge tegnklassenavne i stedet for bogstaveligt at angive sætene som denne, [ \t]
:
$ sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//" < file
Eksempel
$ echo -e " \t blahblah \t " | sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//"
De fleste af GNU-værktøjerne, der bruger regelmæssig ekspre ssions (regex) understøtter disse klasser (her med deres ækvivalenter i den typiske C-lokalitet for et ASCII-baseret system (og kun 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
Brug disse i stedet for bogstavelige sæt virker altid som spild af plads, men hvis du er bekymret for, at din kode er bærbar eller har at gøre med alternative tegnsæt (tænk international), vil du sandsynligvis bruge klassens navne i stedet .
Referencer
Kommentarer
- Bemærk, at
[[:space:]]
ikke svarer til[ \t]
i almindelig sag (unicode osv.).[[:space:]]
vil sandsynligvis være meget langsommere (da der er mange flere typer hvide rum i unicode end bare' '
og'\t'
). Samme ting for alle de andre. -
sed 's/^[ \t]*//'
er ikke bærbar. Til sidst kræver POSIX endda, at for at fjerne en sekvens af mellemrum, tilbageslag ellert
tegn, og at ‘ er hvad GNUsed
gør det også, nårPOSIXLY_CORRECT
er i miljøet. - Hvad hvis jeg vil beskære nye linjer? ‘ \ n \ n tekst \ n \ n ‘
- Jeg kan godt lide sed-løsningen på grund af manglen på andre bivirkninger som i awk-løsningen. Den første variation fungerer ikke, da jeg prøvede det i bash på OSX jsut nu, men tegnklasseversionen fungerer:
sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
- @EugeneBiryukov se min kommentar til det oprindelige indlæg
Svar
xargs uden argumenter gør det.
Eksempel:
trimmed_string=$(echo "no_trimmed_string" | xargs)
Kommentarer
- Dette kontraherer også flere mellemrum inden for en linje, som ikke blev anmodet om i spørgsmålet
- @roaima – sandt, men det accepterede svar klemmer også mellemrum (hvilket ikke blev anmodet om i spørgsmålet). Jeg tror, at det virkelige problem her er, at
xargs
ikke leverer, hvis inputet indeholder tilbageslag og enkelt citater. - @don_crissti, der ikke ‘ t betyder, at det accepterede svar svarer korrekt på spørgsmålet, som det er stillet. Men i dette tilfælde blev det ikke ‘ t markeret som en advarsel, mens det i det accepterede svar var det. Jeg ‘ har forhåbentlig fremhævet det faktum, hvis det ‘ er relevant for en fremtidig læser.
- Det er også bryder på enkelt anførselstegn, dobbelt anførselstegn, omvendt skråstreg tegn. Det kører også en eller flere
echo
påkaldelser. Nogle ekkoimplementeringer behandler også valgmuligheder og / eller tilbageslag … Det fungerer også kun for input med en linje.
Svar
Som foreslået af Stéphane Chazelas i det accepterede svar, kan du nu
oprette et script /usr/local/bin/trim
:
#!/bin/bash awk "{$1=$1};1"
og give den fil eksekverbare rettigheder:
chmod +x /usr/local/bin/trim
Nu kan du sende alle output til trim
for eksempel:
cat file | trim
(til kommentarerne nedenfor: Jeg brugte dette før: while read i; do echo "$i"; done
som også fungerer fint, men er mindre performant)
Kommentarer
- Held og lykke hvis din fil er enorm og / eller indeholder tilbageslag.
- @don_crissti: kunne du kommentere lidt mere ?, hvilken løsning ville være bedre egnet til store filer, og hvordan kunne jeg ændre min løsning, hvis filen indeholdt tilbageslag?
- Du ‘ skal bruge
while read -r line
til at bevare tilbageslag og selv da … . Med hensyn til enorme filer / hastighed valgte du virkelig den værste løsning. Jeg tror ikke ‘ der ‘ er noget værre derude. Se svarene på Hvorfor bruger en shell-løkke til at behandle tekst dårlig praksis? inklusive min kommentar til det sidste svar, hvor jeg tilføjede et link til en speed benchmark.sed
svarene her er helt fine IMO og langt bedre endread
. - Du kan også tilføje et alias i / etc / profil (eller din ~ / .bashrc eller ~ / .zshrc osv …) alias trim = ” awk ‘ { \ $ 1 = \ $ 1}; 1 ‘ ”
- Intet behov for
bash
, du kan gøre det#! /usr/bin/awk -f
{$1=$1};1
. (pas på filnavne, der indeholder=
tegn dog)
Svar
Hvis du gemmer linjer som variabler, kan du bruge bash til at udføre jobbet:
fjern ledende hvidt område fra en streng:
shopt -s extglob echo ${text##+([[:space:]])}
fjern efterfølgende mellemrum fra en streng:
shopt -s extglob echo ${text%%+([[:space:]])}
fjern alt hvidt mellemrum fra en streng:
echo ${text//[[:space:]]}
Kommentarer
- Fjernelse af al hvid plads fra en streng er ikke det samme som at fjerne både ledende og bageste mellemrum (som det er tale om).
- Den bedste løsning – det kræver kun bash-indbyggede og ingen eksterne procesgafler.
- Dejligt. Scripts kører MEGET hurtigere, hvis de ikke ‘ ikke behøver at trække i eksterne programmer (såsom awk eller sed). Dette fungerer også med ” moderne ” (93u +) versioner af ksh.
Svar
sed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//"
Hvis du læser en linje i en shellvariabel, read
gør det allerede medmindre andet er instrueret .
Kommentarer
- +1 for
read
. Så hvis du rører til, mens du læser det, fungerer det:cat file | while read i; do echo $i; done
- @rubo bortset fra at i dit eksempel behandles den ikke-citerede variabel også af skallen. Brug
echo "$i"
for at se den virkelige effekt afread
Svar
For at fjerne alle ledende og bageste mellemrum fra en given linje takket være et “piped” værktøj kan jeg identificere 3 forskellige måder, der ikke er helt ækvivalente. Disse forskelle vedrører mellemrummene mellem inputlinjens ord. Afhængig af det forventede b ehaviour, du vælger.
Eksempler
For at forklare forskellene skal vi overveje denne dummy inputlinje:
" \t A \tB\tC \t "
tr
$ echo -e " \t A \tB\tC \t " | tr -d "[:blank:]" ABC
tr
er virkelig en simpel kommando. I dette tilfælde sletter det ethvert mellemrum eller tabuleringstegn.
awk
$ echo -e " \t A \tB\tC \t " | awk "{$1=$1};1" A B C
awk
sletter ledende og hale mellemrum og klemmer til et enkelt mellemrum hvert mellemrum mellem ord.
sed
$ echo -e " \t A \tB\tC \t " | sed "s/^[ \t]*//;s/[ \t]*$//" A B C
I dette tilfælde sed
sletter ledende og haler mellemrum uden at røre mellemrum mellem ord.
Bemærk:
I tilfælde af et ord pr. linje udfører tr
jobbet.
Kommentarer
- Intet af dette trimmer efterfølgende / førende nye linjer dog
- +1 for en liste over løsninger med deres (undertiden uventede) output.
- @ user61382 dette er ret sent, men se min kommentar til det oprindelige indlæg.
- @highmaintenance: brug
[:space:]
i stedet for [: blank:] til kommandoentr
, ligesom:... | tr -d [:space:]
, for også at fjerne nye linjer. (se:man tr
)
Svar
sed er en godt værktøj til 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 bruge det til din sag, enten rør i teksten, f.eks.
<file sed -e "s/^[[...
eller ved at handle på den “inline”, hvis din sed
er GNU-en:
sed -i "s/..." file
men at ændre kilden på denne måde er “farlig”, da det kan være uopretteligt, når det ikke fungerer rigtigt (eller endda når det gør det!), så sikkerhedskopier først (eller brug -i.bak
som også har fordelen ved at være bærbar til nogle BSD sed
s)!
Svar
Et svar, du hurtigt 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 til at trimme eller bruge .lstrip()
eller .rstrip()
efter behov.
Ligesom rubo77 “sa nswer , gem som script /usr/local/bin/trim
og giv tilladelser med chmod +x
.
Svar
Hvis den streng, man prøver at trimme, er kort og kontinuerlig / sammenhængende, kan man blot sende den som en parameter til enhver bash-funktion:
trim(){ echo $@ } a=" some random string " echo ">>`trim $a`<<" Output >>some random string<<
Svar
Jeg skrev denne shell-funktion ved hjælp af awk
awkcliptor(){ awk -e "BEGIN{ RS="^$" } {gsub(/^[\n\t ]*|[\n\t ]*$/,"");print ;exit}" "$1" ; }
BEGIN{ RS="^$" }
:
i starten før parsering start sæt rekord og separator til ingen dvs. behandle hele input som
en enkelt post
gsub(this,that)
:
erstatte denne regexp med den streng
/^[\n\t ]*|[\n\t ]*$/
:
af denne streng fanger et hvilket som helst præ-newline-område og faneklasse
eller post newline-space og faneklasse og udskift dem med en tom streng
print;exit
: Udskriv og afslut derefter
"$1"
:
og send det første argument for funktionen til være
proces ved awk
hvordan man bruger:
kopiere ovenstående kode, indsæt i shell, og indtast derefter for at definere funktionen.
så kan du bruge awkcliptor som en kommando med det første argument som inputfil
eksempelbrug:
echo " ggggg " > a_file awkcliptor a_file
output:
ggggg
eller
echo -e "\n ggggg \n\n "|awkcliptor
output:
ggggg
Kommentarer
- Kan du venligst forklare forskellen til
awk '{$1=$1};1'
?
Svar
For de af os uden plads nok i hjernen til at huske uklar sed syntaks skal du bare vende strengen , klip det første felt med en afgrænsning af mellemrum, og vend det tilbage igen.
cat file | rev | cut -d" " -f1 | rev
Kommentarer
- Dette fungerer kun, hvis der ikke er mere end et mellemrum, der fører hver linje og ikke mere end et ord i en hvilken som helst 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: udskift str.strip([chars])
med vilkårlige tegn til at trimme eller brug eller .rstrip()
efter behov.
Svar
translate-kommando fungerer
cat file | tr -d [:blank:]
Kommentarer
- Denne kommando er ikke korrekt, da den fjerner alle mellemrum fra filen, ikke kun ledende / efterfølgende mellemrum.
- @BrianRedbeard Du har ret. Dette er stadig et nyttigt svar til en monolitisk streng uden mellemrum.
Svar
til bash-eksempel:
alias trim="awk "{\$1=\$1};1""
brug:
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 blev givet for længe siden. Ideen om at lave et alias ud af det blev foreslået i en kommentar næsten lige så længe siden. Ja, du har lov til at tage en andens kommentar og gøre det til et svar. Men hvis du gør det, skal du give kredit til de mennesker, der sendte ideen foran dig. Og dette er sådan en triviel udvidelse af det accepterede svar, at det ikke rigtig er det værd at gøre. - Idéen var at lave alias. Jeg så ‘ ikke svaret før.
- og anden ting fra stack: ” Tak for feedbacken! Stemmer, der afgives af dem, der har mindre end 15 omdømme, registreres, men ændrer ikke den offentlig viste stilling. ”