2014-04-27 1 views
1

과학적 응용을 위해 python을 사용하고 있습니다. 다양한 매개 변수를 사용하여 시뮬레이션을 실행하면 스크립트는 해당 매개 변수 집합에 대한 적절한 디렉토리로 데이터를 출력합니다. 나중에 그 데이터를 사용합니다. 그러나 때로는 스크립트를 편집합니다. 필요한 경우 내 결과를 재현 할 수 있도록 데이터의 디렉토리에 데이터를 생성하는 데 사용 된 스크립트 버전이 무엇이든 복사본을 갖고 싶습니다. 그래서 기본적으로 내 python 스크립트 자체를 데이터 디렉토리에 복사하고 싶습니다. 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?파이썬 스크립트 자체를 복사하는 가장 좋은 방법은 무엇입니까?

감사합니다.

+3

아 그렇군요. 바이러스를 만들고 싶니? :) – sshashank124

+6

[VCS] (http://en.wikipedia.org/wiki/Revision_control)를 사용하고 데이터와 함께 스크립트의 수정 식별자를 저장하는 것이 좋습니다. –

+0

이것은 XY 문제처럼 들립니다. 당신의 문제 묘사에는 "자기 자신을 복사하는 스크립트"가 나에게 들려오는 어떤 것도 없습니다. 아마도 기본 스크립트를 가지고 있으며, 일부 구성 매개 변수/구성 파일을 가져 와서 다른 스크립트를 실행하여 후행을 위해 다른 곳으로 복사하고 복사 할 수 있습니다 (@MartijnPieters의 VCS 제안은이를 보완 할 수 있습니다.) 저장소에 일반적으로, git repo와 태그를 사용하여 생산 작업 결과를 출력하므로 나중에 언제든지 다시 복제 할 수 있습니다.) – juanchopanza

답변

1

shutil.copy()으로 스크립트를 복사 할 수 있습니다.

하지만 스크립트를 수정 권한으로 유지하는 것이 좋습니다. 이를 통해 개정 내역을 보유 할 수 있습니다.

예. 내 스크립트를 수정 관리하에 git으로 유지합니다. 파이썬 파일에서 나는 이와 같은 버전 문자열을 유지하는 경향이있다.

__version__ = '$Revision: a42ef58 $'[11:-2] 

이 버전 문자열은 문제의 파일이 변경 될 때마다 git 짧은 해시 태그로 업데이트됩니다. 당신은 항상 출력을 생산하고있다 버전을 알 수 있도록 (이 자식의 post-commit 후크에서 update-modified-keywords.py라는 스크립트를 실행하여 수행됩니다.)

이 같은 버전 문자열이있는 경우, 출력에 그것을 포함 할 수 있습니다.

편집는 :

업데이트 - 수정 - 키워드 스크립트는 다음과 같다; 당신이 키워드 확장하여 자식의 역사를 어수선하지 않으려면

#!/usr/bin/env python2 
# -*- coding: utf-8 -*- 
# 
# Author: R.F. Smith <[email protected]> 
# $Date: 2013-11-24 22:20:54 +0100 $ 
# $Revision: 3d4f750 $ 
# 
# To the extent possible under law, Roland Smith has waived all copyright and 
# related or neighboring rights to update-modified-keywords.py. This work is 
# published from the Netherlands. 
# See http://creativecommons.org/publicdomain/zero/1.0/ 

"""Remove and check out those files that that contain keywords and have 
changed since in the last commit in the current working directory.""" 

from __future__ import print_function, division 
import os 
import mmap 
import sys 
import subprocess 


def checkfor(args): 
    """Make sure that a program necessary for using this script is 
    available. 

    Arguments: 
    args -- string or list of strings of commands. A single string may 
      not contain spaces. 
    """ 
    if isinstance(args, str): 
     if ' ' in args: 
      raise ValueError('No spaces in single command allowed.') 
     args = [args] 
    try: 
     with open(os.devnull, 'w') as bb: 
      subprocess.check_call(args, stdout=bb, stderr=bb) 
    except subprocess.CalledProcessError: 
     print("Required program '{}' not found! exiting.".format(args[0])) 
     sys.exit(1) 


def modifiedfiles(): 
    """Find files that have been modified in the last commit. 

    :returns: A list of filenames. 
    """ 
    fnl = [] 
    try: 
     args = ['git', 'diff-tree', 'HEAD~1', 'HEAD', '--name-only', '-r', 
       '--diff-filter=ACMRT'] 
     with open(os.devnull, 'w') as bb: 
      fnl = subprocess.check_output(args, stderr=bb).splitlines() 
      # Deal with unmodified repositories 
      if len(fnl) == 1 and fnl[0] is 'clean': 
       return [] 
    except subprocess.CalledProcessError as e: 
     if e.returncode == 128: # new repository 
      args = ['git', 'ls-files'] 
      with open(os.devnull, 'w') as bb: 
       fnl = subprocess.check_output(args, stderr=bb).splitlines() 
    # Only return regular files. 
    fnl = [i for i in fnl if os.path.isfile(i)] 
    return fnl 


def keywordfiles(fns): 
    """Filter those files that have keywords in them 

    :fns: A list of filenames 
    :returns: A list for filenames for files that contain keywords. 
    """ 
    # These lines are encoded otherwise they would be mangled if this file 
    # is checked in my git repo! 
    datekw = 'JERhdGU='.decode('base64') 
    revkw = 'JFJldmlzaW9u'.decode('base64') 
    rv = [] 
    for fn in fns: 
     with open(fn, 'rb') as f: 
      try: 
       mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) 
       if mm.find(datekw) > -1 or mm.find(revkw) > -1: 
        rv.append(fn) 
       mm.close() 
      except ValueError: 
       pass 
    return rv 


def main(args): 
    """Main program. 

    :args: command line arguments 
    """ 
    # Check if git is available. 
    checkfor(['git', '--version']) 
    # Check if .git exists 
    if not os.access('.git', os.F_OK): 
     print('No .git directory found!') 
     sys.exit(1) 
    print('{}: Updating modified files.'.format(args[0])) 
    # Get modified files 
    files = modifiedfiles() 
    if not files: 
     print('{}: Nothing to do.'.format(args[0])) 
     sys.exit(0) 
    files.sort() 
    # Find files that have keywords in them 
    kwfn = keywordfiles(files) 
    for fn in kwfn: 
     os.remove(fn) 
    args = ['git', 'checkout', '-f'] + kwfn 
    subprocess.call(args) 


if __name__ == '__main__': 
    main(sys.argv) 

, 당신은 얼룩깨끗한 필터를 사용할 수 있습니다. 내 ~/.gitconfig에 다음과 같은 세트가 있습니다.

[filter "kw"] 
    clean = kwclean 
    smudge = kwset 

kwclean과 kwset은 모두 Python 스크립트입니다.

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# 
# Author: R.F. Smith <[email protected]> 
# $Date: 2013-11-24 22:20:54 +0100 $ 
# 
# To the extent possible under law, Roland Smith has waived all copyright and 
# related or neighboring rights to kwset.py. This work is published from 
# the Netherlands. See http://creativecommons.org/publicdomain/zero/1.0/ 

"""Fill the Date and Revision keywords from the latest git commit and tag and 
    subtitutes them in the standard input.""" 

import os 
import sys 
import subprocess 
import re 


def gitdate(): 
    """Get the date from the latest commit in ISO8601 format. 
    """ 
    args = ['git', 'log', '-1', '--date=iso'] 
    dline = [l for l in subprocess.check_output(args).splitlines() 
      if l.startswith('Date')] 
    try: 
     dat = dline[0][5:].strip() 
     return ''.join(['$', 'Date: ', dat, ' $']) 
    except IndexError: 
     raise ValueError('Date not found in git output') 


def gitrev(): 
    """Get the latest tag and use it as the revision number. This presumes the 
    habit of using numerical tags. Use the short hash if no tag available. 
    """ 
    args = ['git', 'describe', '--tags', '--always'] 
    try: 
     with open(os.devnull, 'w') as bb: 
      r = subprocess.check_output(args, stderr=bb)[:-1] 
    except subprocess.CalledProcessError: 
     return ''.join(['$', 'Revision', '$']) 
    return ''.join(['$', 'Revision: ', r, ' $']) 


def main(): 
    """Main program. 
    """ 
    dre = re.compile(''.join([r'\$', r'Date:?\$'])) 
    rre = re.compile(''.join([r'\$', r'Revision:?\$'])) 
    currp = os.getcwd() 
    if not os.path.exists(currp+'/.git'): 
     print >> sys.stderr, 'This directory is not controlled by git!' 
     sys.exit(1) 
    date = gitdate() 
    rev = gitrev() 
    for line in sys.stdin: 
     line = dre.sub(date, line) 
     print rre.sub(rev, line), 


if __name__ == '__main__': 
    main() 

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# 
# Author: R.F. Smith <[email protected]> 
# $Date: 2013-11-24 22:20:54 +0100 $ 
# 
# To the extent possible under law, Roland Smith has waived all copyright and 
# related or neighboring rights to kwclean.py. This work is published from the 
# Netherlands. See http://creativecommons.org/publicdomain/zero/1.0/ 

"""Remove the Date and Revision keyword contents from the standard input.""" 

import sys 
import re 

## This is the main program ## 
if __name__ == '__main__': 
    dre = re.compile(''.join([r'\$', r'Date.*\$'])) 
    drep = ''.join(['$', 'Date', '$']) 
    rre = re.compile(''.join([r'\$', r'Revision.*\$'])) 
    rrep = ''.join(['$', 'Revision', '$']) 
    for line in sys.stdin: 
     line = dre.sub(drep, line) 
     print rre.sub(rrep, line), 

설치되어 이러한 스크립트는 모두 내 $PATH에있는 디렉토리에, 그 실행이 (파일 이름의 끝에 연장하지 않고, 실행 파일에 대한 평소와 같이) 비트 세트.

내 저장소의 파일 .gitattributes에서 키워드 확장을 원하는 파일을 선택합니다. 예를 들어 파이썬 파일;

*.py filter=kw 
+0

좋은 제안 감사! –

+0

나는 당신의 제안을 구현했습니다. 예를 들어 git status를 실행하면 스크립트가 수정 된 것처럼 보일뿐입니다. –

+0

@KaiSikorski 꼭 그렇지는 않습니다. 업데이트 된 답변에 표시된대로'kwset' 및'kwclean' 필터를 * smudge * 및 * clean * 필터로 사용하면 커밋 기록을 엉망으로 만들지 않고 작업 디렉토리에 최신 키워드를 사용할 수 있습니다. –

1

Linux를 사용하는 경우 다음을 사용할 수 있습니다.

import os 
os.system("cp ./scriptname ./") 
0

내가 같은 것을하고 싶었 기 때문에 나는이 질문에 우연히 마주 쳤다. 내가 git/VCS와 함께 개정판과 모든 것이 가장 깨끗한 해결책이 될 것이라는 의견에 동의하지만, 때로는 일을 수행하는 빠르고 더러운 것을 원한다.그래서 사람이 여전히 관심이있는 경우 : __file__

당신은 (경로), 그리고 이미 당신이 어떤 장소에 복사 shutil 같은 높은 수준의 파일 조작 lib 디렉토리를 사용할 수 있습니다 제안 access the running scripts filename 수 있습니다. 해당 수입 및 일부 종과 경적을

shutil.copy(__file__, 'experiment_folder_path/copied_script_name.py') 

: 한 줄에

import shutil 
import os  # optional: for extracting basename/creating new filepath 
import time # optional: for appending time string to copied script 

# generate filename with timestring 
copied_script_name = time.strftime("%Y-%m-%d_%H%M") + '_' + os.path.basename(__file__) 

# copy script 
shutil.copy(__file__, 'my_experiment_folder_path' + os.sep + copied_script_name) 
관련 문제