我有一个日志文件,其中数据以空格分隔。不幸的是,其中一个数据字段也包含空格。我想用“%20”替换这些空格。它看起来像这样:
2012-11-02 23:48:36 INFO 10.2.3.23 something strange name.doc 3.0.0 view1 orientation_right
预期结果是
2012-11-02 23:48:36 INFO 10.2.3.23 something%20strange%20name.doc 3.0.0 view1 orientation_right
无法预测IP地址和“.doc”之间有多少空格。所以我想在可能的情况下使用纯bash在这两种模式之间进行更改。
感谢您的帮助
答案 0 :(得分:1)
$ cat file
2012-11-02 23:48:36 INFO 10.2.3.23 something strange name.doc 3.0.0 view1 orientation_right
使用Perl:
$ perl -lne 'if (/(.*([0-9]{1,3}\.){3}[0-9]{1,3} )(.*)(.doc.*)/){($a,$b,$c)=($1,$3,$4);$b=~s/ /%20/g;print $a.$b.$c;}' file
2012-11-02 23:48:36 INFO 10.2.3.23 something%20strange%20name.doc 3.0.0 view1 orientation_right
答案 1 :(得分:1)
这可能适合你(GNU sed):
sed 's/\S*\s/&\n/4;s/\(\s\S*\)\{3\}$/\n&/;h;s/ /%20/g;H;g;s/\(\n.*\n\)\(.*\)\n.*\n\(.*\)\n.*/\3\2/' file
这会将行拆分为三行,复制该行,用其中一个副本中的space
替换%20
,并重新组合丢弃不需要的行的行。
编辑:
参考下面的评论,上述解决方案可以改为:
sed -r 's/\S*\s/&\n/4;s/.*\.doc/&\n/;h;s/ /%20/g;H;g;s/(\n.*\n)(.*)\n.*\n(.*)\n.*/\3\2/' file
答案 2 :(得分:0)
尚未测试,但在Bash 4中可以这样做
if [[ $line =~ (.*([0-9]+\.){3}[0-9]+ +)([^ ].*\.doc)(.*) ]]; then
nospace=${BASH_REMATCH[3]// /%20}
printf "%s%s%s\n" ${BASH_REMATCH[1]} ${nospace} ${BASH_REMATCH[4]}
fi
答案 3 :(得分:0)
这是GNU sed的一种方式:
echo "2012-11-02 23:48:36 INFO 10.2.3.23 something strange name.doc 3.0.0 view1 orientation_right" |
sed -r 's/(([0-9]+\.){3}[0-9]+\s+)(.*\.doc)/\1\n\3\n/; h; s/[^\n]+\n([^\n]+)\n.*$/\1/; s/\s/%20/g; G; s/([^\n]+)\n([^\n]+)\n([^\n]+)\n(.*)$/\2\1\4/'
输出:
2012-11-02 23:48:36 INFO 10.2.3.23 something%20strange%20name.doc 3.0.0 view1 orientation_right
s/(([0-9]+\.){3}[0-9]+\s+)(.*\.doc)/\1\n\3\n/ # Separate the interesting bit on its own line
h # Store the rest in HS for later
s/[^\n]+\n([^\n]+)\n.*$/\1/ # Isolate the interesting bit
s/\s/%20/g # Do the replacement
G # Fetched stored bits back
s/([^\n]+)\n([^\n]+)\n([^\n]+)\n(.*)$/\2\1\4/ # Reorganize into the correct order
答案 4 :(得分:0)
雷神答案的一个变体,但是使用3个进程(4个跟cat
低于此但你可以通过将your_file作为第一个sed的最后一个参数来摆脱它:
cat your_file |
sed -r -e 's/ (([0-9]+\.){3}[0-9]+) +(.*\.doc) / \1\n\3\n/' |
sed -e '2~3s/ /%20/g' |
paste -s -d " \n"
Thor解释道:
s/ (([0-9]+\.){3}[0-9]+) +(.*\.doc) / \1\n\3\n/
)将有趣位分开。然后:
%20
替换为第二行和每3行的所有空格。必须注意2~3
部分是GNU sed扩展。如果你没有GNU sed,你可以这样做:
cat your_file |
sed -r -e 's/ (([0-9]+\.){3}[0-9]+) +(.*\.doc) / \1\n\3\n/' |
sed -e 'N;P;s/.*\n//;s/ /%20/g;N' |
paste -s -d " \n"
答案 5 :(得分:0)
只是打击。假设在空格分隔的字符串之前出现4个字段,并且在以下字符后出现3个字段:
reformat_line() {
local sep i new=""
for ((i=1; i<=$#; i++)); do
if (( i==1 )); then
sep=""
elif (( (1<i && i<=5) || ($#-3<i && i<=$#) )); then
sep=" "
else
sep="%20"
fi
new+="$sep${!i}"
done
echo "$new"
}
while IFS= read -r line; do
reformat_line $line # unquoted variable here
done < filename
输出
2012-11-02 23:48:36 INFO 10.2.3.23 something%20strange%20name.doc 3.0.0 view1 orientation_right