個別の行を引用符付きのエントリを含むコンマ区切りリストに変換する


15

次のデータ(Rmarkdownファイルから解析されたRパッケージのリスト)があり、それをインストールのためにRに渡すことができるリストにしたい:

d3heatmap
data.table
ggplot2
htmltools
htmlwidgets
metricsgraphics
networkD3
plotly
reshape2
scales
stringr

リストをフォームのリストに変換したい:

'd3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'scales', 'stringr'

現在、生ファイルから上記のリストに移動するbashパイプラインがあります。

grep 'library(' Presentation.Rmd \
| grep -v '#' \
| cut -f2 -d\( \
| tr -d ')'  \
| sort | uniq

新しい行をコンマ区切りリストに変換するためのステップを追加したいと思います。を追加しようとしましたがtr '\n' '","'、失敗します。また、次のスタックオーバーフローの回答をいくつか試しましたが、やはり失敗します。

これがlibrary(stringr)))phics)結果として生成されます。

これが,%結果として生成されます。

この-iフラグ(フラグを削除したもの)は、入力と同じ出力を生成します。


区切り文字はコンマスペースである必要がありますか、それともコンマだけでも受け入れられますか?
スチールドライバー

どちらでも構いませんが、文字列を囲む引用符、'またはが必要"です。
fbt


入力データとそれを処理するスクリプトが完全に互換性がないことに最初に気付きましたか。出力はありません。
ctrl-alt-delor

リストしたスクリプトは、入力データを生成する方法です。誰かがそれを求めました。実際の入力データは次のようになります。Githubはフォーマットを変更して新しい行を削除することに注意してください。
fbt

回答:


19

sedで引用符を追加してから、pasteで行をマージできます:

sed 's/^\|$/"/g'|paste -sd, -

GNU coreutilsベースのシステム(Linuxなど)を実行している場合、末尾のを省略できます'-'

入力したデータにDOSスタイルの行末がある場合(@phkの推奨)、次のようにコマンドを変更できます。

sed 's/\r//;s/^\|$/"/g'|paste -sd, -

1
:MacOSの(そしておそらく他の人)で、あなたは入力がファイルではなく標準入力からのものであることを示すためにダッシュを含める必要がありますsed 's/^\|$/"/g'|paste -sd, -
cherdt

確かに、ペーストの「coreutils」バージョンは両方の形式を受け入れますが、「-」はよりPOSIXです。THX !
ツェッペリン

2
またはsed単独で:sed 's/.*/"&"/;:l;N;s/\n\(.*\)$/, "\1"/;tl'
デジタル外傷

1
@fbt答えの最後に追加したメモもここに適用されます。
phk

1
@DigitalTrauma-あまり良いアイデアではありません。それは非常に遅いでしょう(巨大なファイルでさえハングするかもしれません)-Qに関する私のコメントでリンクされているQIへの答えはここを参照してください。クールなことは、paste単独で使用することです;)
don_crissti

8
を使用してawk
awk 'BEGIN { ORS="" } { print p"'"'"'"$0"'"'"'"; p=", " } END { print "\n" }' /path/to/list
シェルのエスケープが少ないため、読みやすくなります。
awk 'BEGIN { ORS="" } { print p"\047"$0"\047"; p=", " } END { print "\n" }' /path/to/list
出力:
'd3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'scales', 'stringr'
説明:

awkすべてのエスケープせずにスクリプト自体ですBEGIN { ORS="" } { print p"'"$0"'"; p=", " } END { print "\n" }。最初のエントリを出力すると、変数pが設定されます(その前は空の文字列のようです)。この変数を使用すると、pすべてのエントリ(またはawk-speak:record)に接頭辞が付けられ、その周りに一重引用符が追加されて出力されます。awk出力レコードセパレータ変数はORS、空になるように設定されているので(プレフィックスはあなたのためにそれをやっているので)必要とされていませんBEGINING。ああ、ファイルにEND改行を追加することもできます(たとえば、さらにテキスト処理ツールで動作します)。これが不要な場合は、その部分とENDその後のすべて(一重引用符内)を削除できます。

注意

Windows / DOSスタイルの行末(\r\n)がある場合は、\nまずUNIXスタイル()に変換する必要があります。これを行うにtr -d '\015'は、パイプラインの先頭に置くことができます。

tr -d '\015' < /path/to/input.list | awk […] > /path/to/output

\rファイル内でsを使用しないと仮定します。ここでは非常に安全な仮定です。)

または、dos2unix /path/to/input.listファイルをその場で変換するために1回実行するだけです。


このコマンドを実行する', 'stringr23aphicsと、出力が得られます。
fbt

@fbt最新のメモを参照してください。
phk

2
print p"'"'"'"$0"'"'"'"; p=", "—聖句、バットマン!
wchargin

私はright‽:)私は多くのシェルで印刷がいることを言及について考え、知ってp"'\''"$0"'\''";も(それはかかわらPOSIXyではありません)働いていた、または代わりに使用しているだろうbash文字列を引用のCは($'')だけでもprint p"\'"$0"\'";(かかわらず、他のバックスラッシュを倍に必要かもしれません)が、そこののもう1つのメソッドは、awkの文字エスケープを使用しています。
PHK

うわー、あなたがそれを理解したとは信じられません。ありがとうございました。
fbt

6

以下のようdon_crisstiのリンク解答@ショー、信じられないほど速い上のペーストオプションの境界線- Linuxカーネルの配管は、私はちょうど今それを試していなかった場合、私は信じていたよりも効率的です。驚くべきことに、コンマとスペースではなく、リスト項目を区切る単一のコンマで満足できる場合は、貼り付けパイプライン

(paste -d\' /dev/null - /dev/null | paste -sd, -) <input

妥当なflexプログラムよりも高速です(!)

%option 8bit main fast
%%
.*  { printf("'%s'",yytext); }
\n/(.|\n) { printf(", "); }

しかし、まともなパフォーマンスが許容できる場合(そして、ストレステストを実行していない場合、定数係数の差を測定することはできず、それらはすべて瞬時に行われます)、セパレータの柔軟性と妥当なものの両方が必要です-ライナー-y-ness、

sed "s/.*/'&'/;H;1h;"'$!d;x;s/\n/, /g'

あなたのチケットです。はい、それはラインノイズのように見えますが、H;1h;$!d;xイディオムはすべてを丸rightみする正しい方法です。すべてが実際に読みやすくなったことを認識できたら、丸s/.*/'&'/sみとが続きs/\n/, /gます。


編集:不条理に接して、フレックスを取得して他の中空のすべてを打ち負かすことはかなり簡単です。組み込みのマルチスレッド/シグナルハンドラー同期が必要ないことをstdioに伝えるだけです:

%option 8bit main fast
%%
.+  { putchar_unlocked('\'');
      fwrite_unlocked(yytext,yyleng,1,stdout);
      putchar_unlocked('\''); }
\n/(.|\n) { fwrite_unlocked(", ",2,1,stdout); }

ストレス下では、ペーストパイプラインよりも2倍から3倍高速です。


1
(paste -d\ \'\' /dev/null /dev/null - /dev/null | paste -sd, -) <infile | cut -c2-あなたが指摘したようにカンマ+スペース@をほぼ同じ速度で実行しますが、セパレータとしていくつかの派手な文字列が必要な場合は実際には柔軟性がありません
-don_crissti

そのflexようなものはかなりクールな男です... flexこのサイトに誰かがコードを投稿するのを見るのは初めてです...大きな賛成です!このようなものをもっと投稿してください。
-don_crissti

@don_crisstiありがとう!良い機会を探します。sed/ awk / whatnotは​​通常、利便性の値よりも優れたオプションですが、多くの場合、非常に簡単なフレックスの答えもあります。
-jthill

4

Perl

Pythonワンライナー:

$ python -c "import sys; print ','.join([repr(l.strip()) for l in sys.stdin])" < input.txt                               
'd3heatmap','data.table','ggplot2','htmltools','htmlwidgets','metricsgraphics','networkD3','plotly','reshape2','scales','stringr'

単純な方法で動作します-シェルの<演算子を使用してinput.txtをstdinにリダイレクトし、.strip()改行を削除してrepr()各行の引用表現を作成しながら各行をリストに読み込みます。リストは、セパレーターとして.join()、関数を介して1つの大きな文字列に結合されます,

または、+引用符を各ストリップ行に連結するために使用できます。

 python -c "import sys;sq='\'';print ','.join([sq+l.strip()+sq for l in sys.stdin])" < input.txt

Perl

これまでと基本的に同じ考え方:すべての行を読み取り、末尾の改行を削除し、一重引用符で囲み、すべてを配列@cvsに詰め込み、配列値をコンマで結合して出力します。

$ perl -ne 'chomp; $sq = "\047" ; push @cvs,"$sq$_$sq";END{ print join(",",@cvs)   }'  input.txt                        

「d3heatmap」、「data.table」、「ggplot2」、「htmltools」、「htmlwidgets」、「metricsgraphics」、「networkD3」、「plotly」、「reshape2」、「scales」、「stringr」


IIRC、ニシキヘビのはjoinそのためリストにSTDINループを具現化する必要があってはならないイテレータを取ることができるはず
iruvar

@iruvarはい、OPの目的の出力を見る以外は-各単語を引用符で囲み、末尾の改行を削除して出力が1行になるようにする必要があります。リストを理解せずにそれを行う方法を知っていますか?
セルギーKolodyazhnyy

3

あなたがデータがファイルテキストにあると仮定すると、以下はうまくいくはずだと思います

d3heatmap
data.table
ggplot2
htmltools
htmlwidgets
metricsgraphics
networkD3
plotly
reshape2
scales
stringr

コールドダウン置換を持つ配列を使用してみましょう。

#!/bin/bash
input=( $(cat text) ) 
output=( $(
for i in ${input[@]}
        do
        echo -ne "'$i',"
done
) )
output=${output:0:-1}
echo ${output//,/, }

スクリプトの出力は次のようになります。

'd3heatmap', 'data.table', 'ggplot2', 'htmltools', 'htmlwidgets', 'metricsgraphics', 'networkD3', 'plotly', 'reshape2', 'scales', 'stringr'

これはあなたが探していたものだと思いますか?


1
いい解決策。しかし、OPは明示的には要求しませんでしbashたが、誰かがそれを使用する可能性があると想定しても安全ですが(すべての知る限り、最も使用されているシェルです)、それは当然と見なされるべきではありません。また、引用符(二重引用符で囲む)でより良い仕事ができる部分があります。たとえば、パッケージ名にスペースが含まれていることはほとんどありませんが、変数を引用するよりも引用する方が良い慣習です。その上でshellcheck.netを実行し、そこにあるメモと説明を参照してください。
phk

2

多くの場合、非常によく似たシナリオがあります。Excelから列をコピーし、コンテンツをコンマ区切りリストに変換したい(後のSQLクエリで使用するため... WHERE col_name IN <comma-separated-list-here>)。

これは私の.bashrcにあるものです:

function lbl {
    TMPFILE=$(mktemp)
    cat $1 > $TMPFILE
    dos2unix $TMPFILE
    (echo "("; cat $TMPFILE; echo ")") | tr '\n' ',' | sed -e 's/(,/(/' -e 's/,)/)/' -e 's/),/)/'
    rm $TMPFILE
}

次にlbl、入力を待機するcmd行で( "line by line")を実行し、クリップボードからコンテンツを貼り付け、を押す<C-D>と、関数はで囲まれた入力を返します()。これは次のようになります。

$ lbl
1
2
3
dos2unix: converting file /tmp/tmp.OGM6UahLTE to Unix format ...
(1,2,3)

(ここにdos2unixを入れた理由を覚えていないが、これはおそらく会社のセットアップでトラブルを引き起こすことが多いためだろう。)


1

sedの一部のバージョンは少し異なる動作をしますが、私のMacでは、sedの「uniq」以外のすべてを処理できます。

sed -n -e '
# Skip commented library lines
/#/b
# Handle library lines
/library(/{
    # Replace line with just quoted filename and comma
    # Extra quoting is due to command-line use of a quote
    s/library(\([^)]*\))/'\''\1'\'', /
    # Exchange with hold, append new entry, remove the new-line
    x; G; s/\n//
    ${
        # If last line, remove trailing comma, print, quit
        s/, $//; p; b
    }
    # Save into hold
    x
}
${
    # Last line not library
    # Exchange with hold, remove trailing comma, print
    x; s/, $//; p
}
'

残念ながら、ユニークな部分を修正するには、次のようなことをしなければなりません:

grep library Presentation.md | sort -u | sed -n -e '...'

-ポール


2
Unix.stackexchangeへようこそ!ツアーに参加することをお勧めします。
スティーブンラウチ

0

RパッケージをプレーンテキストリストでRにインストールすることは、Rで直接そのリストを使用するソリューションを提案したが、bash、perl、python、awk、sed、または引用符とコンマを入れるものと戦う人は誰もいませんリスト。これはまったく必要ではなく、さらに、Rで変換されたリストを入力および使用する方法を解決しません。

プレーンテキストファイル(前述packages.txt)を単一の変数を持つデータフレームとして読み込むだけで、ベクトルとして直接使用でき、で直接使用できinstall.packagesます。したがって、使用可能なRオブジェクトに変換し、そのリストをインストールするだけです。

df <- read.delim("packages.txt", header=F, strip.white=T, stringsAsFactors=F)
install.packages(df$V1)

または外部ファイルなし:

packages <-" 
d3heatmap
data.table
ggplot2
htmltools
htmlwidgets
metricsgraphics
networkD3
plotly
reshape2
scales
stringr
"
df <- read.delim(textConnection(packages), 
header=F, strip.white=T, stringsAsFactors=F)
install.packages(df$V1)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.