Como você pode combinar todas as linhas que terminam com um caractere de barra invertida?

34

Usando uma ferramenta de linha de comando comum, como sed ou awk, é possível unir todas as linhas que terminam com um determinado caractere, como uma barra invertida?

Por exemplo, dado o arquivo:

foo bar \
bash \
baz
dude \
happy

Eu gostaria de obter este resultado:

foo bar bash baz
dude happy
    
por Cory Klein 24.05.2011 / 01:39

9 respostas

26

uma solução sed mais curta e simples:

sed  '
: again
/\$/ {
    N
    s/\\n//
    t again
}
' textfile

ou one-liner se estiver usando o GNU sed :

sed ':x; /\$/ { N; s/\\n//; tx }' textfile
    
por 24.05.2011 / 13:40
16

É possivelmente mais fácil com perl (já que perl é como sed e awk, espero que seja aceitável para você):

perl -p -e 's/\\n//'
    
por 24.05.2011 / 10:51
16

Aqui está uma solução awk. Se uma linha terminar com \ , retire a barra invertida e imprima a linha sem nova linha final; caso contrário, imprima a linha com uma nova linha final.

awk '{if (sub(/\$/,"")) printf "%s", $0; else print $0}'

Também não é muito ruim em sed, embora o awk seja obviamente mais legível.

    
por 24.05.2011 / 02:14
2

Esta não é uma resposta como tal. É um problema secundário sobre sed .

Especificamente, eu precisava pegar Gilles sed comando separadamente, para entender ... Eu comecei a escrever algumas notas sobre isso, e então achei que poderia ser útil aqui para alguém ...

então aqui está ... Gilles 'sed script no formato documentado :

#!/bin/bash
#######################################
sed_dat="$HOME/ztest.dat"
while IFS= read -r line ;do echo "$line" ;done <<'END_DAT' >"$sed_dat"
foo bar \
bash \
baz
dude \
happy
yabba dabba 
doo
END_DAT

#######################################
sedexec="$HOME/ztest.sed"
while IFS= read -r line ;do echo "$line" ;done <<'END-SED' >"$sedexec"; \
sed  -nf "$sedexec" "$sed_dat"

  s/\$//        # If a line has trailing '\', remove the '\'
                 #    
  t'Hold-append' # branch: Branch conditionally to the label 'Hold-append'
                 #         The condition is that a replacement was made.
                 #         The current pattern-space had a trailing '\' which  
                 #         was replaced, so branch to 'Hold-apend' and append 
                 #         the now-truncated line to the hold-space
                 #
                 # This branching occurs for each (successive) such line. 
                 #
                 # PS. The 't' command may be so named because it means 'on true' 
                 #     (I'm not sure about this, but the shoe fits)  
                 #
                 # Note: Appending to the hold-space introduces a leading '\n'   
                 #       delimiter for each appended line
                 #  
                 #   eg. compare the hex dump of the follow 4 example commands:  
                 #       'x' swaps the hold and patten spaces
                 #
                 #       echo -n "a" |sed -ne         'p' |xxd -p  ## 61 
                 #       echo -n "a" |sed -ne     'H;x;p' |xxd -p  ## 0a61
                 #       echo -n "a" |sed -ne   'H;H;x;p' |xxd -p  ## 0a610a61
                 #       echo -n "a" |sed -ne 'H;H;H;x;p' |xxd -p  ## 0a610a610a61

   # No replacement was made above, so the current pattern-space
   #   (input line) has a "normal" ending.

   x             # Swap the pattern-space (the just-read "normal" line)
                 #   with the hold-space. The hold-space holds the accumulation
                 #   of appended  "stripped-of-backslah" lines

   G             # The pattern-space now holds zero to many "stripped-of-backslah" lines
                 #   each of which has a preceding '\n'
                 # The 'G' command Gets the Hold-space and appends it to 
                 #   the pattern-space. This append action introduces another
                 #   '\n' delimiter to the pattern space. 

   s/\n//g       # Remove all '\n' newlines from the pattern-space

   p             # Print the pattern-space

   s/.*//        # Now we need to remove all data from the pattern-space
                 # This is done as a means to remove data from the hold-space 
                 #  (there is no way to directly remove data from the hold-space)

   x             # Swap the no-data pattern space with the hold-space
                 # This leaves the hold-space re-initialized to empty...
                 # The current pattern-space will be overwritten by the next line-read

   b             # Everything is ready for the next line-read. It is time to make 
                 # an unconditional branch  the to end of process for this line
                 #  ie. skip any remaining logic, read the next line and start the process again.

  :'Hold-append' # The ':' (colon) indicates a label.. 
                 # A label is the target of the 2 branch commands, 'b' and 't'
                 # A label can be a single letter (it is often 'a')
                 # Note;  'b' can be used without a label as seen in the previous command 

    H            # Append the pattern to the hold buffer
                 # The pattern is prefixed with a '\n' before it is appended

END-SED
#######
    
por 24.05.2011 / 18:01
2

Ainda outra ferramenta de linha de comando comum seria ed , que por padrão modifica arquivos no local e, portanto, deixa as permissões de arquivo inalteradas (para obter mais informações sobre ed consulte Editando arquivos com o editor de texto ed a partir de scripts )

str='
foo bar \
bash 1 \
bash 2 \
bash 3 \
bash 4 \
baz
dude \
happy
xxx
vvv 1 \
vvv 2 \
CCC
'

# We are using (1,$)g/re/command-list and (.,.+1)j to join lines ending with a '\'
# ?? repeats the last regex search.
# replace ',p' with 'wq' to edit files in-place
# (using Bash and FreeBSD ed on Mac OS X)
cat <<-'EOF' | ed -s <(printf '%s' "$str")
H
,g/\$/s///\
.,.+1j\
??s///\
.,.+1j
,p
EOF
    
por 22.05.2012 / 12:48
2

Usando o fato de que read no shell interpretará as barras invertidas quando usado sem -r :

$ while IFS= read line; do printf '%s\n' "$line"; done <file
foo bar bash baz
dude happy

Observe que isso também interpretará qualquer outra barra invertida nos dados.

    
por 02.08.2018 / 14:20
1

Uma solução simples (r) que carrega todo o arquivo na memória:

sed -z 's/\\n//g' file                   # GNU sed 4.2.2+.

Ou ainda um curto que funciona com linhas de entendimento (saída) (sintaxe GNU):

sed ':x;/\$/{N;bx};s/\\n//g' file

Em uma linha (sintaxe POSIX):

sed -e :x -e '/\$/{N;bx' -e '}' -e 's/\\n//g' file

Ou use o awk (se o arquivo for grande demais para caber na memória):

awk '{a=sub(/\$/,"");printf("%s%s",$0,a?"":RS)}' file
    
por 02.08.2018 / 13:00
0

A versão para Mac baseada na solução @Giles seria semelhante a esta

sed ':x
/\$/{N; s|\'$'\n||; tx
}' textfile

Onde a principal diferença é como as novas linhas são representadas e a combinação de qualquer outra em uma linha quebra-a

    
por 14.06.2017 / 16:32
-1

Você pode usar o cpp, mas ele produz algumas linhas vazias onde ele mescla a saída, e alguma introdução que eu removo com sed - talvez isso também possa ser feito com cpp-flags e opções:

echo 'foo bar \
bash \
baz
dude \
happy' | cpp | sed 's/# 1 .*//;/^$/d'
foo bar bash baz
dude happy
    
por 22.05.2012 / 03:39