web-dev-qa-db-fra.com

Comment pouvez-vous combiner toutes les lignes qui se terminent par un caractère de barre oblique inverse?

Utilisation d'un outil de ligne de commande commune comme SED ou AWK, est-il possible de rejoindre toutes les lignes qui se terminent par un caractère donné, comme une barre oblique inverse?

Par exemple, étant donné le fichier:

foo bar \
bash \
baz
dude \
happy

Je voudrais obtenir cette sortie:

foo bar bash baz
dude happy
37
Cory Klein

une solution de SED plus courte et plus simple:

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

ou une doublure si vous utilisez GNU sed:

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

C'est peut-être plus facile avec Perl (puisque Perl est comme SED et Awk, j'espère que cela vous est acceptable):

Perl -p -e 's/\\\n//'
20
camh

Voici une solution AWK. Si une ligne se termine par un \, dépouiller la barre oblique inverse et imprimez la ligne sans terminer la nouvelle ligne; Sinon, imprimez la ligne avec une ligne de terminaison.

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

Ce n'est pas non plus trop mal dans SED, bien que AWK soit évidemment plus lisible.

Ce n'est pas une réponse en tant que telle. C'est une question de côté sur sed.

Plus précisément, j'avais besoin de prendre des Gilles sed commandement à l'autre pièce par pièce pour le comprendre ... J'ai commencé à écrire quelques notes dessus, puis pensais que cela peut être utile ici à quelqu'un ...

alors, voici ... Gilles 'sed script In documenté Format:


#!/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
#######
3
Peter.O

Utiliser le fait que read dans la coquille interprétera les barres arrière lorsqu'il est utilisé sans -r:

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

Notez que cela interprétera également tout Autre Backslash dans les données.

2
Kusalananda

Encore un autre outil de ligne de commande commune serait ed, qui modifie par défaut les fichiers en place et laisse donc des autorisations de fichier non modifiées (pour plus d'informations sur ed voir Modification des fichiers avec le ed Éditeur de texte des 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
2
verdo

Une solution simple (R) qui charge le fichier entier en mémoire:

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

Ou un toujours court qui fonctionne de la compréhension (sortie) (Syntaxe GNU):

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

Sur une ligne (syntaxe POSIX):

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

Ou utilisez AWK (si le fichier est trop gros pour s'adapter à la mémoire):

awk '{a=sub(/\\$/,"");printf("%s%s",$0,a?"":RS)}' file
1
Isaac

La version Mac basée sur la solution @giles ressemblerait à ceci

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

Où la principale différence correspond à la manière dont les nouvelles lignes sont représentées et que vous combinez plus loin dans une ligne le casse

0
Andy