2015-02-07 52 views
-1

请帮我以下的问题:变化符合脚本(Python或bash)的

(1)我需要找到一个文件夹中的所有* .txt文件夹及其子 ( 2)在这些纯文本文件中,有一行以“#GAP:6009,27”开头。我想在所有文件中改变这个值,减少175。例如:之前:“#GAP:6009,27”,之后:“#GAP:5834,27”。

文本文件包含很多行,只有特定的行应该更改。例如:

[...] 
#MedleyEndBeat:790 
#BPM:335,53 
#GAP:6009,27 
#ENCODING:CP1252 
[...] 

我该如何做到这一点?

我的想法:

找到所有的txt文件,并运行Python脚本

find musicdir -name \*.txt -exec ./mypythonscript {} \;" 

Python脚本包含像这样(只是想法,语法是完全错误的,我知道,但我会看它后来):

filepath = open($1) 
with open(filepath) as file: 
    for line in file: 
     if line[0:5] == "#GAP:" then 
      newvalue = calc(line[6:]-175) # extract substring (the GAP value till end of line) 
      newfile += "#GAP:" + newvalue 
      GAP_FOUND = 1 
     else 
      newfile += line 
write(filepath) << newfile 
if GAP_FOUND != 1 then 
    echo "ERROR: GAP LINE NOT FOUND IN"+filepath 

那么有没有更好的方法来做到这一点?或者可以这样做?我不是专业的编码器,这就是为什么我的方法可能看起来不好:)

+0

有很多方法可以做到这一点,但如果你已经知道python,那么这看起来很好。就我个人而言,我会制作一个更改后的文件的副本,只有当你知道内容全部写完,但可能比你需要的更偏执狂 – 2015-02-07 08:52:45

+0

你走在正确的轨道上,但你绝对可以更优雅。你可以让python脚本自己找到所有的文件。您可以使用多个上下文管理器一次打开多个文件,并且可以更有效地利用内存。 Gap_found应该只是一个布尔值。如果你想超级漂亮,那么你可以使用线程或多处理来做得更快。 – 2015-02-07 09:09:00

+0

谢谢大家!我学到了很多。很多不同的方法来解决这个问题=) – merlin 2015-02-07 16:34:20

回答

0

这是所有可行的纯粹在Python,但我怀疑你可以把它作为如果这是对雅致的可接受度量,那么它就相当于相应的shell脚本。

find . -name '*.txt' -print0 | 
xargs -0 sh -c 'for file; do 
    awk -F "[:,]" "/^#GAP:/ { 
     g=\$2-175; o=\":\" \$2 \","; sub(o, \":\" g ","); x=1 } 1 
    END { exit 1-x }" "$file" >"$file.tmp" && 
    mv "$file.tmp" "$file" || rm "$file.tmp"; done' _ 

find产生匹配文件名的列表。sh脚本在这些文件上循环(最后参数_有点瑕疵; sh -c 'script...'之后的第一个参数是在脚本中使用argv[0]的值),并且Awk脚本查找匹配并产生退出代码这表明它是否被发现。在成功的情况下,生成的临时输出文件将移到输入文件的顶部;否则,临时文件将被丢弃(以免更改内容未更改的文件)。

如果文件中的分隔符是统一的,Awk脚本可能会简单得多。事实上,我不得不强制一些东西,所以这个剧本的主体根本不是很优雅。

0

我刚刚写了一个小的bash脚本,实际上比做洞工作。你不需要python来实现这一点。这只是一个基本的破解,我已经在Mac OS X和Ubuntu上进行了测试。在其他版本的Linux/Unix上可能会有一些问题。所以在运行之前在你的系统上进行测试。

我也为代码添加了一些评论,所以你可以看到并学习会发生什么。

#!/bin/bash 
# the dir that will be searched 
musicdir="/home/user/music" 
# amount to deduct from GAP 
subamount=127 

new_gap() 
{ 
    # replace "," by "." 
    line=`echo $1|sed 's/,/\\./g'` 
    # deduct 
    nv=`bc -l <<< "scale=2; $line-$subamount"` 
    # replace "." by "," 
    line=`echo $nv|sed 's/\\./,/g'` 
    # return new value 
    echo $line 
} 

for file in `find $musicdir -iname "*.txt"`; do 
    while read p; do 
     # regex to match the #GAP: line 
     GAP=`[[ $p =~ ^"#GAP:"(.*)$ ]] && echo ${BASH_REMATCH[1]}` 
     # if we found the wanted line, we process it 
     if [ ! -z "$GAP" ]; then 
      # the value of the #GAP: line is now in the var $GAP (without the start: #GAP:) 
      # we pass it to the function "new_gap" so there can be a new value calculated 
      # and returned (echo). the new line will then saved in the file 
      echo "#GAP:"$(new_gap $GAP) 
     # if it is a normal line, just write it back to the file 
     else 
      echo $p 
     fi 
    done <$file>$file.new 
    # now be make a backup of the original file 
    mv "$file" "$file.back" 
    # and copy the new file to the original location 
    mv "$file.new" "$file" 
done 
0

此致对于fileinput模块,该标准输入从文件名的列表连接到文件的内容,以及任选的作业,通过使用inplace开关的重定向标准输出到相同的文件。

$ cat decrement.py 
import fileinput 
import sys 

start = sys.argv[1] ; l = len(start) 
delta = int(sys.argv[2]) 
files = sys.argv[3:] 

for line in fileinput.input(files, inplace=True): 
    if line.startswith(start): 
     items = line[l:].split(',') 
     items[0] = str(int(items[0])-delta) 
     print(start+','.join(items), end='') 
    else: 
     print(line, end='') 
$ python3 decrement.py "#GAP:" 185 `find musicdir -name \*.txt` 

请注意,我们不得不引用#GAP:,因为散列是大多数shell的注释字符。

虽然脚本使用print,但是没有输出产生到stdout,因为fileinputstdout映射到被覆盖的文件。实际上,临时文件用于最大限度地减少与不完整运行相关的风险,但这对程序员来说是完全透明的。

如果你愿意使用python2,使用print line,带有尾随逗号,以避免在输出空白行...

+0

非常感谢。有一个小问题,您的脚本只接受UTF8文件,否则会出现错误,例如“UnicodeDecodeError:'utf-8'编解码器无法解码字节0xe4的位置:无效的连续字节ISO-8859”。所有文件的编码是不同的。将所有文件转换为utf-8后,我工作得很好。谢谢! – merlin 2015-02-07 16:32:34