3

I have a log file where data is separated by spaces. Unfortunately one of the datafields contains spaces as well. I would like to replace those spaces with "%20". It looks like this:

2012-11-02 23:48:36 INFO 10.2.3.23 something strange name.doc 3.0.0 view1 orientation_right

the expected result is

2012-11-02 23:48:36 INFO 10.2.3.23 something%20strange%20name.doc 3.0.0 view1 orientation_right

unpredictable that how many spaces we have between the IP address and ".doc". So I would like to change them between these two patterns using pure bash if possible.

thanks for the help

4

6 に答える 6

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

これにより、行が3つに分割され、行がコピーされ、コピーの1つで' spacesが'に置き換えられ、行%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
于 2012-11-04T09:08:33.073 に答える
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
于 2012-11-04T07:19:19.630 に答える
0

GNUsedの1つの方法は次のとおりです。

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
于 2012-11-04T09:23:15.970 に答える
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
于 2012-11-04T12:35:12.087 に答える
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
于 2012-11-04T08:00:46.957 に答える
0

Thorの回答のバリエーションですが、3つのプロセスを使用します(4つはcatベローですが、最初のsedの最後の引数としてyour_fileを配置することでそれを取り除くことができます):

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"

トールが説明したように:

  • 最初の sed ( s/ (([0-9]+\.){3}[0-9]+) +(.*\.doc) / \1\n\3\n/) は、関心のあるビットを独自の行に分離します。

その後:

  • %202 番目の sed は、2 行目と 3 行ごとにすべてのスペースを by に置き換えます。
  • 最後に、貼り付けて元に戻します。

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"
于 2012-11-04T10:14:17.583 に答える