Jak mohu oříznout úvodní a koncové mezery z každého řádku nějakého výstupu?

Chtěl bych odstranit všechny úvodní a koncové mezery a karty z každého řádku výstupu.

Existuje jednoduchý nástroj jako trim Mohl bych svůj výstup propojit?

Příklad souboru:

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 

Komentáře

  • Každému, kdo zde hledá řešení pro odstranění nových řádků, jde o jiný problém. Podle definice nový řádek vytvoří nový řádek textu. Řádek textu proto nemůže obsahovat nový řádek. Otázkou, na kterou se chcete zeptat, je, jak odstranit nový řádek od začátku nebo konce řetězce: stackoverflow.com/questions/369758 nebo jak odstranit prázdný řádek řádky nebo řádky, které jsou pouze prázdné znaky: serverfault.com/questions/252921

Odpovědět

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

nebo kratší:

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

Ořízlo by vedení a koncové mezery nebo znaky tabulátoru 1 a také mačkat sekvence karet a mezery do jednoho prostoru.

To funguje, protože když něco přiřadíte jednomu z polí , awk znovu vytvoří celý záznam. (jak je vytištěno print) spojením všech polí ($1, …, $NF) s OFS (ve výchozím nastavení mezera).

1 (a případně další prázdný znak s v závislosti na národním prostředí a awk implementaci)

Komentáře

  • středník na druhý příklad je nadbytečný. Může použít: awk '{$1=$1}1'
  • @Brian, ne, ; je vyžadován ve standardní syntaxi awk
  • Zajímavé … gawk, mawk a OS X ‚ s awk nepodporují žádný středník. (Alespoň pro mé verze (1.2, 4.1.1 a 20070501, v uvedeném pořadí)
  • Jediná věc, která se mi na tomto přístupu nelíbí ‚ je, že ztratit opakující se mezery v řádku. Například echo -e 'foo \t bar' | awk '{$1=$1};1'
  • echo ' hello ' | xargs

Odpověď

Příkaz může být zkrácen, takže pokud používáte GNU sed:

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

Příklad

Zde je výše uvedený příkaz v akci.

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

Pomocí hexdump můžete potvrdit, že příkaz sed správně odstraňuje požadované znaky.

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

Třídy znaků

Místo doslovného výpisu sad, jako je tento, můžete použít i názvy tříd znaků, [ \t]:

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

Příklad

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

Většina nástrojů GNU, které využívají pravidelné expre ssions (regex) podporují tyto třídy (zde s jejich ekvivalentem v typickém národním prostředí C systému založeného na ASCII (a pouze tam)).

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

Použití tyto namísto doslovných množin vždy vypadají jako plýtvání prostorem, ale pokud se zajímáte o to, zda je váš kód přenosný, nebo se musíte vypořádat s alternativními znakovými sadami (myslím mezinárodně), pravděpodobně budete místo toho chtít použít názvy tříd .

Odkazy

Komentáře

  • Upozorňujeme, že [[:space:]] není ekvivalentem [ \t] v obecný případ (unicode atd.). [[:space:]] bude pravděpodobně mnohem pomalejší (protože v unicode je mnohem více typů mezer než jen ' ' a '\t'). Totéž pro všechny ostatní.
  • sed 's/^[ \t]*//' není přenosný. POSIX dokonce vyžaduje, aby odstranil posloupnost mezery, zpětného lomítka nebo t znaků, a to ‚ je tím, co GNU sed také dělá, když je POSIXLY_CORRECT v prostředí.
  • Co když chci oříznout znaky nového řádku? ‚ \ n \ n text \ n \ n ‚
  • Líbí se mi řešení sed kvůli nedostatku další vedlejší účinky jako v awk řešení. První varianta nefunguje, když jsem ji nyní vyzkoušel v bash na OSX, ale verze třídy znaků funguje: sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
  • @EugeneBiryukov viz můj komentář původní příspěvek

Odpověď

xargs bez argumentů to dělá.

Příklad:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

Komentáře

  • Tím se také uzavře více mezer v rámci řádek, který nebyl v otázce požadován
  • @roaima – pravda, ale přijatá odpověď také stlačí mezery (což v dotazu nebylo požadováno). Myslím, že skutečným problémem zde je, že xargs se nezobrazí, pokud vstup obsahuje zpětná lomítka a jednoduché uvozovky.
  • @don_crissti, který Neznamená to však, že přijatá odpověď správně odpovídá na otázku, jak byla položena. Ale v tomto případě to nebylo ‚ označeno jako upozornění, zatímco v přijaté odpovědi to bylo. Doufám, že jsem ‚ zdůraznil skutečnost pro případ, že by to ‚ bylo relevantní pro budoucího čtenáře.
  • Také konce jednoduchých uvozovek, uvozovek, zpětných lomítek. Spouští také jednu nebo více echo vyvolání. Některé implementace ozvěny také zpracují možnosti a / nebo zpětná lomítka … To funguje pouze pouze pro jednořádkový vstup.

Odpovědět

Jak navrhuje Stéphane Chazelas v přijaté odpovědi, nyní můžete
vytvořit skript /usr/local/bin/trim:

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

a udělit tomuto souboru práva ke spuštění:

chmod +x /usr/local/bin/trim 

Nyní můžete předat všechny výstupy do trim, například:

cat file | trim 

(pro komentáře níže: Použil jsem to dříve: while read i; do echo "$i"; done
, který také funguje dobře, ale je méně výkonný)

Komentáře

  • Hodně štěstí, pokud je váš soubor obrovský a / nebo obsahuje zpětná lomítka.
  • @don_crissti: můžete okomentovat ještě trochu více ?, které řešení by být vhodnější pro velké soubory a jak mohu upravit své řešení, pokud soubor obsahoval zpětná lomítka?
  • ‚ Budete muset použít while read -r line k uchování zpětných lomítek a i tehdy … . Pokud jde o obrovské soubory / rychlost, opravdu jste zvolili nejhorší řešení. ‚ si nemyslím, že by tam ‚ bylo něco horšího. Podívejte se na odpovědi Proč se ke zpracování špatného postupu textu používá smyčka prostředí? včetně mého komentáře k poslední odpovědi, kde jsem přidal odkaz na test rychlosti. Odpovědi sed jsou naprosto v pořádku IMO a mnohem lepší než read.
  • Alias můžete přidat také do / etc / profile (nebo váš ~ / .bashrc nebo ~ / .zshrc atd …) alias trim = “ awk ‚ { \ $ 1 = \ $ 1}; 1 ‚ “
  • Není potřeba bash, můžete to udělat #! /usr/bin/awk -f {$1=$1};1. (pozor na názvy souborů, které obsahují = znaků)

Odpověď

Pokud ukládáte řádky jako proměnné, můžete k provedení úlohy použít bash:

odstranit úvodní mezery z řetězce:

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

odstranit koncové mezery z řetězce:

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

odebrat všechny mezery z řetězce:

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

Komentáře

  • Odstranění veškerého prázdného místa z řetězce není totéž jako odebrání úvodních i koncových mezer (jako u dotyčných).
  • Daleko nejlepší řešení – vyžaduje pouze integrované bash a žádné externí vidlice procesu.
  • Pěkné. Skripty spouští LOT rychleji, pokud ‚ nemusí stahovat externí programy (například awk nebo sed). Toto funguje také s “ moderními “ (93u +) verzemi ksh.

Odpověď

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

Pokud čtete řádek do proměnné prostředí, read dělá to již , pokud není uvedeno jinak .

Komentáře

  • +1 pro read. Pokud tedy při čtení používáte kanál, funguje to: cat file | while read i; do echo $i; done
  • @rubo kromě toho ve vašem příkladu je nekódovaná proměnná přepracována i shellem. Použijte echo "$i" pro zobrazení skutečného efektu read

Odpověď

Chcete-li pomocí nástroje „piped“ odstranit z daného řádku všechny úvodní a koncové mezery, mohu identifikovat 3 různé způsoby, které nejsou zcela ekvivalentní. Tyto rozdíly se týkají mezer mezi slovy vstupního řádku. V závislosti na očekávaném b ehaviour, vyberete si.

Příklady

Chcete-li vysvětlit rozdíly, zvažte tento fiktivní vstupní řádek:

" \t A \tB\tC \t " 

tr

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

tr je opravdu jednoduchý příkaz. V takovém případě odstraní jakýkoli znak mezery nebo tabulátoru.

awk

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

awk odstraní mezery mezi předními a zadními mezerami a vmáčkne všechny mezery mezi slovy do jedné mezery.

sed

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

V tomto případě sed odstraní mezery mezi předními a zadními mezerami bez dotyku mezer mezi slovy.

Poznámka:

V případě jednoho slova na řádek provede úkol tr.

Komentáře

  • Žádná z těchto možností ale nezastaví koncové / vedoucí nové řádky
  • +1 pro seznam řešení s jejich (někdy neočekávaným) výstupem.
  • @ user61382 to je dost pozdě, ale viz můj komentář k původnímu příspěvku.
  • @highmaintenance: použijte [:space:], místo [: blank:], pro příkaz tr, například: ... | tr -d [:space:], aby odstranil i nové řádky. (viz: man tr)

Odpověď

sed je skvělý nástroj k tomu:

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

Můžete jej použít pro svůj případ buď v textu, například

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

nebo jednáním „inline“, pokud váš sed je ten GNU:

sed -i "s/..." file 

ale změna zdroje tímto způsobem je „nebezpečná“, protože může být neobnovitelná, pokud nefunguje správně (nebo dokonce i když funguje!), proto nejprve proveďte zálohu (nebo použijte -i.bak který má také tu výhodu, že je přenosný na některé BSD sed s)!

Odpovědět

Odpověď, které můžete pochopit na první pohled:

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

Bonus: replace str.strip([chars]) s libovolnými znaky, které můžete podle potřeby oříznout nebo použít .lstrip() nebo .rstrip().

Jako rubo77 „sa nswer , uložte jako skript /usr/local/bin/trim a udělejte oprávnění pomocí chmod +x.

Odpověď

Pokud je řetězec, který se pokoušíte oříznout, krátký a spojitý / souvislý, lze jej jednoduše předat jako parametr na jakoukoli funkci bash:

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

odpověď

Tuto funkci shellu jsem napsal pomocí awk

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

BEGIN{ RS="^$" }:
na začátku, než začne analyzovat nastavený záznam
oddělovač na žádný tj. zacházet s celým vstupem jako s jediným záznamem

gsub(this,that):
nahradit tento regulární výraz tímto řetězcem

/^[\n\t ]*|[\n\t ]*$/:
tohoto řetězce zachytí jakýkoli prostor pro nový řádek a třídu karet
nebo zveřejní prostor pro nový řádek a třídu karet a nahradí je
prázdným řetězcem

print;exit: poté vytiskněte a ukončete

"$1":
a předejte první argument funkce být
zpracovat awk

jak používat:
zkopírovat výše uvedený kód, vložit do shellu a poté zadat
definovat funkce.
pak můžete použít awkcliptor jako příkaz s prvním argumentem jako vstupním souborem

ukázkové použití:

echo " ggggg " > a_file awkcliptor a_file 

výstup:

ggggg 

nebo

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

výstup:

ggggg 

Komentáře

  • Můžete mi prosím vysvětlit rozdíl jen awk '{$1=$1};1'?

Odpověď

Pro ty z nás, kteří nemají dostatek místa v mozku, aby si pamatovali nejasnou syntaxi sed, stačí obrátit řetězec , vystřihněte první pole s oddělovačem prostoru a vraťte jej zpět zpět.

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

Komentáře

  • Toto funguje pouze v případě, že v každém řádku není více než jedna mezera a v žádném řádku není více než jedno slovo.

Odpovědět

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: nahraďte str.strip([chars]) libovolnými znaky pro oříznutí nebo použijte nebo .rstrip() podle potřeby.

Odpovědět

příkaz translate bude fungovat

cat file | tr -d [:blank:] 

Komentáře

  • Tento příkaz není správný, protože odstraní všechny mezery ze souboru, nejen úvodní / koncové mezery.
  • @BrianRedbeard Máte pravdu. Toto je stále užitečná odpověď pro monolitický řetězec bez mezer.

Odpověď

pro příklad bash:

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

využití:

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

výsledek:

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

Komentáře

  • Odpověď awk '{$1=$1};1' byla poskytnuta již dávno. Myšlenka vytvořit z něj alias byla navržena v komentáři téměř stejně dávno. Ano, můžete vzít komentář někoho jiného a proměnit jej v odpověď. Pokud to však uděláte, měli byste uznat lidi, kteří tento nápad zveřejnili před vámi. A toto je tak triviální rozšíření přijaté odpovědi, že to za to opravdu nestojí.
  • Myšlenkou bylo vytvořit alias. ‚ Tuto odpověď jsem předtím neviděl.
  • a druhá věc ze zásobníku: “ Děkujeme za zpětnou vazbu! Hlasy odevzdané těmi, kteří mají méně než 15 reputací, jsou zaznamenány, ale nemění veřejně zobrazené skóre příspěvku. “

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *