在对其进行一些更改后替换文件中的字符串

时间:2012-12-24 11:05:00

标签: linux bash sed awk

任务:

我收到了一个带字幕的文件,时间非常糟糕。所有这些都是相同的时间。我想在它们上运行一个脚本来添加/减去一定的时间。我试图通过linux中的命令行来做到这一点。所以我试图使用awk和/或sed。不过,我对他们没有经验。

我要改变的字符串如下所示:01:35:12,300

问题:

使用awk我设法写了一个脚本文件,我可以像这样调用:

awk -f subtitles_shift.awk change="-01:00:11" subtitle_sample

我的脚本基本上做的是:它将文件中的字符串以及作为参数传递的字符串转换为秒。进行更改,转换回字符串,然后再将整个事件吐出。它有效。

唯一的问题是,我现在不知道如何将这些更改写回文件......

我瘦了什么:

我认为,我应该使用sed来完成工作,因为它允许我写回文件。但是使用sed我不知道如何编写这样一个脚本,在应用替换字符串之前对搜索字符串进行计算。

sed 's/..:..:..,.../REPLACEMENT/' <old >new

在给予sed替换字符串之前,如何对匹配的模式进行所有必要的计算?

我希望你明白,我的意思......

最后但并非最不重要:

提前多多感谢!

代码示例 - 代码示例

这是我的awk脚本的主要部分:

# looking for the lines that hold the time strings
/^..:/ {
    # picking the first and third column. These are the times
    start = $1; 
    end   = $3;
    # calculating changes by invoking functions
    start_new = alter_time(start, change, sign);
    end_new   = alter_time(end, change, sign);
}

可能的解决方案

天啊,是的!我可以处理所有内容,在必要的行上进行数学运算,并将所有行写回文件。到目前为止,这似乎有效:

{
    if ($1 ~ /^..:/) {

        start = $1;
        end   = $3;

        start_new = alter_time(start, change, sign);
        end_new   = alter_time(end, change, sign);

        print start_new " --> " end_new > "times.srt";
    } else {
        print $0 > "times.srt";
    }
}

2 个答案:

答案 0 :(得分:2)

您可以使用就地减法,即获取字幕文件,然后使用awk解析,直至达到时间格式(广告已完成)

然后使用awk语言的time function,在现场减去并替换。

或者,你可以使用这样的东西进行减法,(感谢glenn

awk -v 'time=16:13:04,699' -v "date=$(date +%H:%M:%S)" '
  function abs(x) {return x<0 ? -x : x}
  BEGIN {
    split(time, ary, /[:,]/); t_sec = 3600*ary[1] + 60*ary[2] + ary[3]
    split(date, ary, /:/);    d_sec = 3600*ary[1] + 60*ary[2] + ary[3]
    # output difference in minutes
    print abs(t_sec - d_sec)/60
  }
'

我认为你不需要sed,无论如何,祝你好运。

答案 1 :(得分:1)

很可能远非完美。但那是我到目前为止提出的剧本。而且,嘿,这是它的工作; - )

我的第一个awk脚本,顺便说一句,所以请耐心等待,但请随时指出所有的弱点......

#!/usr/bin/awk -f

# invoke me like this:
#
# [awk -f] subtitles_shift.awk var="-01:42:09" file.srt
#
# @ var     the shift forward or backward
# @ file    the srt file to be processed
#
# fractions of seconds are ignored. the script gives the 
# following format back:
# HH:MM:SS,000 --> HH:MM:SS,000
# 
# the script saves to a file named times.srt in the
# current directory.

#############################################
# BEGIN
#############################################

BEGIN {
    print "\nstarting script (subtitles_shift.awk):";
    # get the first variable passed
    var = ARGV[1];
    # assign only the value
    split(var, a, "=");
    change = a[2];
    # assign the operation (addition or subtraction)
    sign = check_sign(change);
    # trim a possible sign from the variable
    sub(/^[^0-9]/, "", change);
    print "the time shift will be: " , sign change;
    print "--------------------------------------";
}

function convert_time_string_to_sec(string) 
{
    # string should be of the format 00:00:00,0[00]
    split(string, a, ":");
    split(a[3], b, ",");
    hh = a[1];
    mm = a[2];
    ss = b[1];
    # calculate the total time in seconds
    return ( hh * 3600 + mm * 60 + ss );
}

function add_leading_zero(str)
{
    if (length(str) == 1) {
        str = ( "0" str );
    }
    return str;
}

function trim_fraction(str)
{
    split(str, array, ".");
    return array[1];
}

function convert_sec_to_string(sec)
{
    # get hours as a fraction
    hours  = sec / 3600;
    # only take complete hours
    h  = trim_fraction(hours);
    # add a leading zero (if necessary)
    hh = add_leading_zero(h);
    # subtract full hours from sec
    sec -= ( h * 3600 );
    # get minutes as a fraction
    min  = sec / 60;
    # only take complete minutes
    m  = trim_fraction(min);
    # add a leading zero (if necessary)
    mm = add_leading_zero(m);
    # subtract full minutes from sec
    sec -= ( m * 60 );
    # add a leading zero (if necessary)
    ss = add_leading_zero(sec);
    # prepare full string and return it
    string = ( hh ":" mm ":" ss ",000" );
    return string;
}

function alter_time(time_str, alter_str, sign)
{
    # get time in seconds
    sec = convert_time_string_to_sec(time_str);
    dif = convert_time_string_to_sec(alter_str);
    # add or subtract according to sign
    if (sign == "+") {
        new = sec + dif;
    } else {
        new = sec - dif;
    }
    # convert back to a string (00:00:00,000) and return
    newstr = convert_sec_to_string(new);
    return newstr;
}

function check_sign(str)
{
    # check for a sign, if none assume addition
    first  = substr(str, 0, 1);
    if (first == "-")
        return "-";
    else
        return "+";
}

#############################################
# main block
#############################################

{
    # if the line starts with time string
    if ($1 ~ /^..:/) {
        # assign start and end time
        start = $1;
        end   = $3;
        # run the main function to change according to argument passed
        start_new = alter_time(start, change, sign);
        end_new   = alter_time(end, change, sign);
        # print the new line to file (string --> string)
        print start_new " --> " end_new > "times.srt";
    } else {
        line = $0;
        # trim line feeds (appeared on my linux machine ^M at eol)
        gsub(/[:\015]/, "", line);
        # print the line to file
        print line > "times.srt";
    }
}

#############################################
# END
#############################################

END {
    print "file times.srt created.";
    print "--------------------------------------";
}