use*_*man 21 shell text-processing
我必须以这种格式获取 IP 地址列表(负载):
134.27.128.0
111.245.48.0
109.21.244.0
Run Code Online (Sandbox Code Playgroud)
并将它们转换为这种格式,中间有一个管道(IP 组成)
134.27.128.0 | 111.245.48.0 | 109.21.244.0 | 103.22.200.0/22
Run Code Online (Sandbox Code Playgroud)
我认为这是一个查找和替换命令,sed
但我无法让它工作。
ste*_*ver 16
使用 sed,基于Famous Sed One-Liners Explained, Part I: : 39. 如果下一行以反斜杠“\”结尾,则在下一行追加一行(除了这里我们忽略关于反斜杠的部分,并将\n
换行符替换为所需的|
分隔符):
sed -e :a -e '$!N; s/\n/ | /; ta' mydoc > mydoc2
Run Code Online (Sandbox Code Playgroud)
应该在 mydoc2
134.27.128.0 | 111.245.48.0 | 109.21.244.0
Run Code Online (Sandbox Code Playgroud)
don*_*sti 12
我很想知道其中一些(+ 一些替代方案)如何在相当大的文件(163MiB
,IP
每行一个,约 1300 万行)中快速工作:
wc -l < iplist
13144256
Run Code Online (Sandbox Code Playgroud)
结果(sync; echo 3 > /proc/sys/vm/drop_caches
在每个命令之后;我重复了测试 - 以相反的顺序 - 几个小时后,但差异可以忽略不计;另请注意,我正在使用gnu sed
):
steeldriver:
非常慢。等待两分钟后中止......所以没有结果。
昆林:
awk 'FNR!=1{print l}{l=$0};END{ORS="";print l}' ORS=' | ' iplist
real 0m3.672s
perl -pe 's/\n/ | / unless eof' iplist
real 0m12.444s
Run Code Online (Sandbox Code Playgroud)
迈克服务:
paste -d\ /dev/null iplist /dev/null | paste -sd\| -
real 0m0.983s
Run Code Online (Sandbox Code Playgroud)
小山:
sed 'H;1h;$!d;x;s/\n/ | /g' iplist
real 0m4.903s
Run Code Online (Sandbox Code Playgroud)
阿维纳什·拉吉:
time python2.7 -c'
import sys
with open(sys.argv[1]) as f:
print " | ".join(line.strip() for line in f)' iplist
real 0m3.434s
Run Code Online (Sandbox Code Playgroud)
和
val0x00ff :
while read -r ip; do printf '%s | ' "$ip"; done < iplist
real 3m4.321s
Run Code Online (Sandbox Code Playgroud)
这意味着184.321s
. 不出所料,这比mikeserv的解决方案慢 200 倍。
以下是
awk 的其他一些方法:
awk '$1=$1' RS= OFS=' | ' iplist
real 0m4.543s
awk '{printf "%s%s",sep,$0,sep=" | "} END {print ""}' iplist
real 0m5.511s
Run Code Online (Sandbox Code Playgroud)
珀尔:
perl -ple '$\=eof()?"\n":" | "' iplist
real 0m9.646s
Run Code Online (Sandbox Code Playgroud)
参数:
xargs <iplist printf ' | %s' | cut -c4-
real 0m6.326s
Run Code Online (Sandbox Code Playgroud)
head+paste+tr+cat的组合:
{ head -n -1 | paste -d' |' - /dev/null /dev/null | tr \\n \ ; cat ; } <iplist
real 0m0.991s
Run Code Online (Sandbox Code Playgroud)
如果您有GNU coreutils
并且您的 IP 列表不是很大(假设多达 50000 个 IP),您也可以使用以下命令执行此操作pr
:
pr -$(wc -l infile) -tJS' | ' -W1000000 infile >outfile
Run Code Online (Sandbox Code Playgroud)
在哪里
-$(wc -l infile) # no. of columns (= with no. of lines in your file)
-t # omit page headers and trailers
-J # merge lines
-S' | ' # separate columns by STRING
-W1000000 # set page width
Run Code Online (Sandbox Code Playgroud)
例如对于 6 行文件:
134.28.128.0
111.245.28.0
109.245.24.0
128.27.88.0
122.245.48.0
103.44.204.0
Run Code Online (Sandbox Code Playgroud)
命令:
pr -$(wc -l <infile) -tJS' | ' -W1000 infile
Run Code Online (Sandbox Code Playgroud)
输出:
134.28.128.0 | 111.245.28.0 | 109.245.24.0 | 128.27.88.0 | 122.245.48.0 | 103.44.204.0
Run Code Online (Sandbox Code Playgroud)
您可以使用awk:
awk 'FNR!=1{print l}{l=$0};END{ORS="";print l}' ORS=' | ' file > new_file
Run Code Online (Sandbox Code Playgroud)
ORS=' | '
将输出记录分隔符设置为' | '
而不是换行符。
或使用perl
以下命令就地编辑:
perl -pe 's/\n/ | / unless eof' file
Run Code Online (Sandbox Code Playgroud)
小智 6
带有 tr 和 sed 的单线:
cat file | tr '\n' '|' | sed 's/||$/\n/'
134.27.128.0|111.245.48.0|109.21.244.0
Run Code Online (Sandbox Code Playgroud)
所以我整个事情都错了——这个问题教会了我很多关于……的知识paste
。正如 cuonglm 正确指出的那样,除非您paste
在串行中使用 in 文件-s
,否则您总是会在写入时将 infile 列表中的最后一个\n
ewline 附加到输出中。我错误地认为paste -s
行为是其默认模式——这是一种误解,显然busybox
paste
很乐意强化这种误解。以下命令确实按照 w/ 所宣传的那样工作busybox
:
paste -d'| ' - - infile </dev/null >outfile
Run Code Online (Sandbox Code Playgroud)
但它不能按照规范工作。正确实现的paste
仍然会\n
为每个写入的序列附加一个尾随的 ewline。不过,这毕竟没什么大不了的:
paste -d\ - infile - </dev/null | paste -sd\| - >outfile
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
32387 次 |
最近记录: |