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 nebot
znaků, a to ‚ je tím, co GNUsed
také dělá, když jePOSIXLY_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ědised
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 efekturead
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říkaztr
, 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. “