我有以下数据(从 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' '","'
,但失败了。我还尝试了以下一些 Stack Overflow 答案,但也失败了:
这产生了library(stringr)))phics)
结果。
这产生了,%
结果。
这个答案(-i
删除标志)产生与输入相同的输出。
答案1
您可以添加引号sed然后将行与粘贴, 像那样:
sed 's/^\|$/"/g'|paste -sd, -
如果您运行的是基于 GNU coreutils 的系统(即 Linux),则可以省略结尾的'-'
.
如果您输入的数据具有 DOS 风格的行结尾(如 @phk 建议),您可以按如下方式修改命令:
sed 's/\r//;s/^\|$/"/g'|paste -sd, -
答案2
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:记录) 是前缀,并且另外打印时用单引号括起来。不需要输出记录分隔符变量(因为前缀已经为您完成了),因此在 ing 时将其设置为awk
空。哦,我们可能会在文件中添加换行符(例如,这样它可以与其他文本处理工具一起使用);如果不需要,则可以删除其后的部分及其后的所有内容(单引号内)。ORS
BEGIN
END
END
如果您有 Windows/DOS 样式的行结尾 ( \r\n
),则必须先将它们转换为 UNIX 样式 ( \n
)。为此,您可以将其放在tr -d '\015'
管道的开头:
tr -d '\015' < /path/to/input.list | awk […] > /path/to/output
\r
(假设您的文件中没有任何 s 用途。这里是非常安全的假设。)
或者,只需运行dos2unix /path/to/input.list
一次即可就地转换文件。
答案3
作为@don_crissti 的链接答案表明,粘贴选项的速度快得令人难以置信——Linux 内核的管道比我现在没有尝试过的更高效。值得注意的是,如果您对用单个逗号分隔列表项而不是逗号+空格感到满意,那么粘贴管道
(paste -d\' /dev/null - /dev/null | paste -sd, -) <input
甚至比合理的程序还要快flex
(!)
%option 8bit main fast
%%
.* { printf("'%s'",yytext); }
\n/(.|\n) { printf(", "); }
但是,如果体面的性能是可以接受的(并且如果您没有运行压力测试,您将无法测量任何常数因子差异,它们都是即时的)并且您希望分离器既具有灵活性又具有合理性-线性度,
sed "s/.*/'&'/;H;1h;"'$!d;x;s/\n/, /g'
是你的票。是的,它看起来像线路噪音,但这个H;1h;$!d;x
习语是吸收所有内容的正确方法,一旦你认识到整个内容实际上变得很容易阅读,后面就会s/.*/'&'/
出现 slurp 和s/\n/, /g
.
编辑:近乎荒谬,让 flex 击败其他一切是相当容易的,只需告诉 stdio 你不需要内置的多线程/信号处理程序同步:
%option 8bit main fast
%%
.+ { putchar_unlocked('\'');
fwrite_unlocked(yytext,yyleng,1,stdout);
putchar_unlocked('\''); }
\n/(.|\n) { fwrite_unlocked(", ",2,1,stdout); }
在压力下,它比粘贴管道快 2-3 倍,而粘贴管道本身比其他管道快至少 5 倍。
答案4
Python
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'
工作方式很简单 - 我们使用 shell 的<
运算符将 input.txt 重定向到 stdin,将每一行读入列表,.strip()
删除换行符并repr()
创建每行的带引号的表示形式。然后通过函数将列表连接成一个大字符串.join()
,并,
使用分隔符
或者,我们可以使用+
将引号连接到每个剥离的行。
python -c "import sys;sq='\'';print(','.join([sq+l.strip()+sq for l in sys.stdin]))" < input.txt
珀尔
本质上与以前的想法相同:读取所有行,删除尾随换行符,用单引号引起来,将所有内容填充到数组 @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'