バックスラッシュ文字で終わるすべての行をどのように組み合わせることができますか?


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
良いもの...私は最初にこれを見て理解できませんでした(そのため、あまりにも硬いバスケットには入りませんでした)...しかし、Gillesの答えを詳しく調べた後(かなり時間がかかりました)私はあなたの答えをもう一度見て、それは非常に理解しやすいように見えましたsed:私は理解し始めていると思います:)...あなたは各行をパターンスペースに直接追加し、「正常終了」行が来ると、パターンスペース全体が落ちて自動印刷されます(-nオプションがないため)... .. +1
Peter.O

@fred:おかげで、私はあまりにもsedを理解し始めていると思う、それは複数行の編集のための素晴らしいツールを提供していますが、どのようにミックスアップするためにそれらあなたは簡単ではありませんも可読性がトップである...必要なものを手に入れる
neurino

DOSの行末に注意してください。キャリッジリターンまたは\ r!
user77376

1
何が問題になっているsed -e :a -e '/\\$/N; s/\\\n//; ta'
アイザック

18

これはおそらくperlで最も簡単です(perlはsedとawkに似ているため、受け入れられることを望みます):

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

短くてシンプルで、私はその1つが好きです+1そして彼はsedやawkを明示的に要求しませんでした
rudolfson


2

これ自体は答えではありません。これはについての副次的な問題ですsed

具体的には、sedそれを理解するために、Gillesのコマンドを1つずつ分解する必要がありました...それについてメモを書き始め、それがここで誰かに役立つかもしれないと考えました...

そうここにある...ジル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
Neurinoのソリューションは実際には非常に簡単です。やや複雑なsedといえば、これは興味を引くかもしれません
ジル 'SO-悪であるのをやめる'

2

さらに別の一般的なコマンドラインツールはed、デフォルトでファイルをその場で変更するため、ファイルのアクセス許可は変更されません(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
アイザック

@Isaacああ、多分私は「他のバックスラッシュを解釈する」と言うべきだったのでしょうか?
クサラナナンダ

1

メモリ内のファイル全体をロードするsimple(r)ソリューション:

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

または、(出力)行の理解に役立つ(GNU構文)まだ短いもの:

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

1行(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ソリューションに基づくMacバージョンは次のようになります

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

主な違いは、改行の表示方法であり、それ以上を1つの行に結合すると壊れます


-1

cppを使用できますが、出力をマージした空の行がいくつか生成され、sedで削除した導入部分があります-cpp-flagsとオプションでも同様に実行できます。

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

解決策cpp 確かですか?あなたの例ではecho、二重引用符で囲まれたwith文字列はすでに直線化されたテキストを出力しているのでcpp、意味がありません。(これはsedコードにも当てはまります。)文字列を一重引用符でcpp囲むと、バックスラッシュが削除されるだけで、行は連結されません。(cppバックスラッシュの前にスペースがなければ連結は機能しますが、別の単語はセパレータなしで結合されます。)
manatwork

@manatwork:Outsch!:) sedコマンドが機能したことに驚いたが、もちろんsedコマンドではなかったが、bash自体はバックスラッシュ改行を前の行の継続として解釈する。
ユーザー不明

cppそれでもそのように使用すると、行が連結されません。の使用sedは間違いなく不要です。使用cpp -P:「-Pプリプロセッサからの出力でのラインマーカーの生成を禁止します。」– man cpp
manatwork

あなたのコマンドは私には機能しません: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 --versionが明らかにcpp (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3-何ですか?Ubuntuはcppにパッチを適用していますか?どうして?私は、GNU ...読むことを期待しているだろう
ユーザー不明

面白い。Ubuntuはcpp実際に行を連結し、いくつかの空白を残します。さらに興味深いことに、同じバージョン4.4.3-4ubuntu5.1はここで受け入れます-P。ただし、ラインマーカーが削除されるだけで、空の行は残ります。
マナトワーク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.