Ters eğik çizgi karakteriyle biten tüm çizgileri nasıl birleştirirsiniz?


35

Sed veya awk gibi ortak bir komut satırı aracı kullanarak, ters eğik çizgi gibi belirli bir karakterle biten tüm satırları birleştirmek mümkün mü?

Örneğin, dosyaya verilen:

foo bar \
bash \
baz
dude \
happy

Bu çıktıyı almak istiyorum:

foo bar bash baz
dude happy

1
Dosyayı geçerek cpp:)
imz - Ivan Zakharyaschev

Pek çok harika cevap, keşke hepsini cevap olarak işaretleyebilseydim! Awk, sed ve perl'ye iyi baktığın için teşekkürler, bunlar harika örneklerdi.
Cory Klein

Yanıtlar:


26

daha kısa ve daha basit bir sed çözüm:

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

veya GNU kullanıyorsanız bir astar sed:

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

1
iyi bir ... Ben esasen buna baktım ve anlayamadım (bu yüzden çok zor bir sepete girmedi) ... ama Gilles'un cevabına derinlemesine baktıktan sonra (oldukça zaman aldı) Cevabınıza bir kez daha baktım ve anlaşılır bir şekilde anlaşılır görünüyordu, anlamaya başladığımı düşünüyorum sed:) ... Her bir satırı doğrudan kalıp boşluğuna ekliyorsunuz ve "normal olarak biten" bir satır geldiğinde, tüm desen alanı düşer ve otomatik olarak yazdırır (çünkü -n seçeneği yoktur) ... temiz! .. +1
Peter.O

@ fred: teşekkürler, ben de sed'i anlamaya başladığımı düşünüyorum, çok satırlı düzenleme için güzel araçlar sunuyor, ancak ihtiyacınız olanı elde etmek için bunları nasıl karıştıracağınız basit değil ya da okunabilirlik en üst düzeyde ...
neurino

DOS satır sonlarına dikkat et, aka. taşıma iadesi veya r!
user77376

1
Neyin varsed -e :a -e '/\\$/N; s/\\\n//; ta'
Isaac

18

Perl ile muhtemelen en kolay (perl sed ve awk gibi olduğundan, sizin için kabul edilebilir olduğunu umuyorum):

perl -p -e 's/\\\n//'

kısa ve basit, ben bunu
beğenmiştim


2

Bu böyle bir cevap değil. Bu bir yan konudur sed.

Spesifik olarak, onu sedanlamak için Gilles'yu parça parça ayırmam gerekiyordu ... Üzerine bazı notlar yazmaya başladım ve sonra bunun burada birileri için yararlı olabileceğini düşündüm ...

işte o ... Gilles' sed komut dosyası içinde belgelenmiştir formata:


#!/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
#######

1
Neurino'nun çözümü aslında oldukça basittir. Hafif derecede karmaşık sed'den bahsetmek, bu ilginizi çekebilir .
Gilles 'SO- kötülük'

2

Diğer bir yaygın komut satırı aracı ed, varsayılan olarak yerinde dosyaları değiştirir ve bu nedenle dosya izinlerini değiştirilmemiş halde bırakır (daha fazla bilgi için, edbkz. Dosyaları komut dizilerinden ed metin düzenleyicisiyle düzenleme ).

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

readOlmadan kullanıldığında kabuğunda ters eğik çizgi yorumlayacağı gerçeğini kullanarak -r:

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

Bunun , verilerdeki diğer ters eğik çizgileri de yorumlayacağını unutmayın .


Hayır! Tüm ters eğik çizgiyi kaldırmaz . Deneyina\\b\\\\\\\\\\\c
Isaac

@Iacac Ah, belki de "başka bir ters eğik çizgi yorumla" demeliydim?
Kusalananda

1

Tüm dosyayı belleğe yükleyen basit (r) bir çözüm:

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

Veya anlama (çıktı) satırlarını (GNU sözdizimi) anlamaya çalışan kısa bir yazı:

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

Bir satırda (POSIX sözdizimi):

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

Veya awk kullanın (dosya belleğe sığmayacak kadar büyükse):

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

0

@Giles çözümünü temel alan Mac sürümü şöyle görünür

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

Asıl fark, yeni satırların nasıl temsil edildiği ve herhangi bir satırda bir satırda bir araya gelmesi, onu keser.


-1

Cpp'yi kullanabilirsiniz, ancak çıktıyı birleştirdiği bazı boş satırlar ve sed ile kaldırdığım bazı girişler oluşturur - belki de cpp-flag'leri ve seçenekleriyle yapılabilir:

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

Emin misiniz cpp olduğu bir çözüm? Örnekte echozaten çıkışlar metni düzleştirilmiş çift tırnak içinde dize ile, bu nedenle cppanlamsızdır. (Bu aynı zamanda uygulanır sedTekli tırnak içinde dize koyarsanız,. Kod) cppsadece ters eğik çizgi kaldırır ancak satırları birleştirir. (Birleştirme cpp, ters eğik çizgilerden önce boşluk olmazsa işe yarar, ancak daha sonra ayrı kelimeler ayırıcılar olmadan birleştirilir.)
Manatwork

@ manatwork: Outsch! :) Sed komutunun işe yaramasına şaşırmıştım, ama elbette, sed komutu değildi, ama bash ters eğik çizgi-linebreak işlevini önceki satırın devamı olarak yorumluyor.
kullanıcı bilinmeyen

Kullanılması cppböyle hala benim için değil satırları birleştirir. Ve kullanımı sedkesinlikle gereksizdir. Kullanın cpp -P: “ -PÖnişlemcinin çıktısında
linarkarker

Sizin komut benim için çalışmaz: cpp: “-P: No such file or directory cpp: warning: '-x c' after last input file has no effect cpp: unrecognized option '-P:' cpp: no input filesA cpp --versionaçığa cpp (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3- ne? Ubuntu cpp ekliyor mu? Neden? GNU'yu okumayı umuyordum ...
kullanıcı bilinmeyen

İlginç. Ubuntu'nun cppgerçekten çizgileri birleştiriyor ve bazı boşluklar bırakıyor. Daha da ilginç olanı, 4.4.3-4ubuntu5.1 versiyonunun burada kabul ettiği -P. Bununla birlikte, yalnızca kaplama kalemlerini ortadan kaldırır, boş çizgiler kalır.
Manatwork
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.