आप बैकस्लैश कैरेक्टर के साथ समाप्त होने वाली सभी लाइनों को कैसे जोड़ सकते हैं?


36

एक सामान्य कमांड लाइन टूल जैसे कि sed या awk का उपयोग करना, क्या किसी दिए गए वर्ण के साथ समाप्त होने वाली सभी लाइनों को बैकस्लैश की तरह जोड़ना संभव है?

उदाहरण के लिए, फ़ाइल दी गई:

foo bar \
bash \
baz
dude \
happy

मैं यह आउटपुट प्राप्त करना चाहूंगा:

foo bar bash baz
dude happy

1
फाइल पास करें cpp:)
imz - Ivan Zakharyaschev

इतने शानदार जवाब, काश मैं उन सभी को जवाब के रूप में चिह्नित कर सकता! Awk, sed, और perl पर शानदार नज़र के लिए धन्यवाद, ये महान उदाहरण थे।
कोरी क्लेन

जवाबों:


27

एक छोटा और सरल sed समाधान:

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

या एक-लाइनर अगर GNU का उपयोग कर रहे हैं sed:

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

1
अच्छा एक ... मैंने इसे देखा और इसे समझ नहीं सका (इसलिए यह बहुत मुश्किल टोकरी में नहीं था) ... लेकिन गाइल्स के उत्तर पर गहराई से देखने के बाद (जो कि काफी समय लगा) मुझे आपके उत्तर पर एक और नज़र थी और यह उल्लेखनीय रूप से समझ में आता था कि मुझे लगता है कि मैं समझना शुरू कर रहा हूं sed:) ... आप प्रत्येक पंक्ति को सीधे पैटर्न-स्पेस में जोड़ रहे हैं, और जब "सामान्य रूप से समाप्त" लाइन के साथ आता है, पूरे पैटर्न स्पेस के माध्यम से और ऑटो प्रिंट (क्योंकि कोई विकल्प नहीं है) गिरता है ... साफ! .. +1
पीटरो

@ पसंदीदा: मुझे लगता है कि मुझे लगता है कि मैं भी सेड को समझना शुरू कर रहा हूं, यह मल्टीलाइन एडिटिंग के लिए अच्छे टूल प्रदान करता है, लेकिन उन्हें कैसे मिलाएं, जो आपको चाहिए, वह सीधा नहीं है और न ही पठनीयता शीर्ष पर है ...
न्यूरोइन

डॉस लाइन एंडिंग, उर्फ ​​से सावधान रहें। कैरिज रिटर्न या \ r!
user77376

1
क्या गलत हैsed -e :a -e '/\\$/N; s/\\\n//; ta'
आइजैक

18

यह संभवतः पर्ल के साथ सबसे आसान है (क्योंकि पर्ल सीड और ऑक की तरह है, मुझे उम्मीद है कि यह आपके लिए स्वीकार्य है):

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

लघु और सरल, मुझे यह पसंद है कि एक +1 और उसने सरल रूप से sed या awk के लिए नहीं पूछा था
rudolfson

17

यहाँ एक अजीब समाधान है। यदि एक रेखा के साथ समाप्त होता है \, तो बैकस्लैश को हटा दें और बिना किसी समाप्ति के न्यूलाइन के साथ लाइन प्रिंट करें; अन्यथा नई समाप्ति रेखा के साथ लाइन प्रिंट करें।

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

यह सीड में भी बहुत बुरा नहीं है, हालांकि जाग स्पष्ट रूप से अधिक पठनीय है।


2

यह इस तरह का जवाब नहीं है। यह एक साइड इश्यू है sed

विशेष रूप से, मुझे sedइसे समझने के लिए गाइल्स कमांड को टुकड़े से अलग करने की आवश्यकता थी ... मैंने इस पर कुछ नोट्स लिखना शुरू किया, और फिर सोचा कि यह किसी के लिए उपयोगी हो सकता है ...

तो यहाँ यह है ... दस्तावेज प्रारूप में गिल्स की पटकथा :


#!/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
न्यूरोिनो का समाधान वास्तव में बहुत सरल है। हल्के से जटिल सेड की बात करें, तो यह आपको रूचि दे सकता है
गिल्स एसओ- बुराई को रोकना '24

2

फिर भी एक अन्य सामान्य कमांड लाइन टूल होगा ed, जो डिफ़ॉल्ट रूप से फाइलों को इन-प्लेस में संशोधित करता है और इसलिए फ़ाइल अनुमतियों को बिना अनुमति के छोड़ देता है (अधिक जानकारी के लिए स्क्रिप्ट्स से एड टेक्स्ट एडिटर के साथ फाइल एडिटिंगed देखें )

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

इस तथ्य का उपयोग करना कि readबिना उपयोग किए जाने पर शेल बैकस्लैश की व्याख्या करेगा -r:

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

ध्यान दें कि यह डेटा में किसी अन्य बैकस्लैश की भी व्याख्या करेगा ।


नहीं। यह सभी बैकस्लैश को नहीं हटाएगा । के साथ प्रयास करेंa\\b\\\\\\\\\\\c
इसहाक

@ इसाक आह, शायद मुझे "किसी अन्य बैकस्लैश की व्याख्या" करनी चाहिए थी?
कुसलानंद

1

एक सरल (r) समाधान जो पूरी फ़ाइल को मेमोरी में लोड करता है:

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

या अभी भी एक छोटा है जो समझ (आउटपुट) लाइनों (GNU वाक्य रचना) को काम करता है:

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

एक पंक्ति (POSIX सिंटैक्स) पर:

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

या awk का उपयोग करें (यदि फ़ाइल मेमोरी में फिट होने के लिए बहुत बड़ी है):

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

0

@Giles समाधान पर आधारित मैक संस्करण इस तरह दिखेगा

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

जहां मुख्य अंतर यह है कि कैसे नई रेखाओं का प्रतिनिधित्व किया जाता है, और किसी भी एक पंक्ति में संयोजन करने से यह टूट जाता है


-1

आप cpp का उपयोग कर सकते हैं, लेकिन यह कुछ खाली लाइनों का उत्पादन करता है जहां यह आउटपुट को मर्ज करता है, और कुछ परिचय जो मैं sed के साथ हटाता हूं - शायद यह cpp- झंडे और विकल्पों के साथ भी किया जा सकता है:

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

क्या आप सुनिश्चित हैं cpp कि एक समाधान है? आपके उदाहरण echoमें डबल-कोट्स में स्ट्रिंग पहले से ही सीधे टेक्स्ट को आउटपुट करता है, इसलिए cppयह बेकार है। (यह आपके sedकोड पर भी लागू होता है ।) यदि आप स्ट्रिंग को सिंगल-कोट्स में रखते हैं, cppतो बैकस्लैश को हटा देता है, लेकिन लाइनों को नहीं जोड़ता है। ( cppयदि कोई बैकस्लैश से पहले कोई स्थान नहीं होगा, लेकिन तब अलग-अलग शब्दों को बिना विभाजकों के साथ जोड़ा जाएगा, तब काम करेगा।)
मैनटवर्क

@manatwork: बाहरी! :) मैं चकित था, कि sed कमांड ने काम किया है, लेकिन निश्चित रूप से, यह sed कमांड नहीं था, लेकिन बैश खुद पिछली लाइन की निरंतरता के रूप में बैकलैश-लाइनब्रेक की व्याख्या करता है।
उपयोगकर्ता अज्ञात

cppउस तरह का उपयोग करना अभी भी मेरे लिए लाइनों को समाप्‍त नहीं करता है। और का उपयोग sedनिश्चित रूप से अनावश्यक है। उपयोग करें cpp -P: " -Pप्रीप्रोसेसर से आउटपुट में लाइनमार्कर्स का अवरोध।" - आदमी cpp
मैनटवर्क

आपकी आज्ञा मेरे काम नहीं आती: 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 filesएक cpp --versionखुलासा cpp (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3- क्या? Ubuntu पैचिंग है? क्यूं कर? मुझे GNU पढ़ने की उम्मीद होगी ...
उपयोगकर्ता अज्ञात

दिलचस्प। उबंटू cppवास्तव में लाइनों को समेटता है और कुछ खाली छोड़ देता है। और भी दिलचस्प, वही संस्करण 4.4.3-4ubuntu5.1 यहाँ स्वीकार करता है -P। हालाँकि यह केवल लाइनमार्क को समाप्त करता है, खाली रेखाएँ बनी रहती हैं।
मैनटवर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.