这是@Luke's answer的轻微改进。它做了两个小的改进:
#!/usr/bin/python
# Downloaded from https://stackoverflow.com/questions/1510105/gnupg-how-to-edit-the-file-without-decrypt-and-save-to-local-disk-first/12289967#12289967
# and then slightly improved.
import os, sys, subprocess, getpass, stat, shutil
editor = 'nano'
dataFile = sys.argv[1]
## make a backup of the encrypted file
bakFile = dataFile+'-gpgedit_backup'
shutil.copy(dataFile, bakFile)
dstat = os.stat(dataFile)
## create temporary directory in tmpfs to work from
tmpDir = '/dev/shm/gpgedit'
n = 0
while True:
try:
os.mkdir(tmpDir+str(n))
break
except OSError as err:
if err.errno != 17: ## file already exists
raise
n += 1
tmpDir += str(n)
os.chmod(tmpDir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
reEncrypted = False
try:
## Get password
passwd = getpass.getpass()
## decrypt file
tmpFile = os.path.join(tmpDir, 'data')
cmd = "gpg -d --cipher-algo AES256 --passphrase-fd 0 --output %s %s" % (tmpFile, dataFile)
proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
proc.stdin.write(passwd)
proc.stdin.close()
if proc.wait() != 0:
raise Exception("Error decrypting file.")
## record stats of tmp file
stat = os.stat(tmpFile)
## invoke editor
os.system('%s %s' % (editor, tmpFile))
## see whether data has changed
stat2 = os.stat(tmpFile)
if stat.st_mtime == stat2.st_mtime and stat.st_size == stat2.st_size:
print "Data unchanged; not re-writing encrypted file."
else:
## re-encrypt, write back to original file
reEncrypted = True
cmd = "gpg --yes --symmetric --cipher-algo AES256 --passphrase-fd 0 --output %s %s" % (dataFile, tmpFile)
proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
proc.stdin.write(passwd)
proc.stdin.close()
if proc.wait() != 0:
raise Exception("Error encrypting file.")
except:
## If there was an error AND re-encryption was attempted, restore the backup.
if reEncrypted:
print "Error occurred; restoring encrypted file from backup."
shutil.copy(bakFile, dataFile)
raise
finally:
shutil.rmtree(tmpDir)
os.remove(bakFile)
我会将这些建议的改进作为对@Luke 答案的评论发布——我非常喜欢——但没有足够的声誉点来这样做。:(