如何改进这个 Python / Xonsh 脚本(从 bash 转换而来)?

如何改进这个 Python / Xonsh 脚本(从 bash 转换而来)?

我开始学习xonsh和Python。我想主要使用 Python 来编写 shell 脚本,并且想替换许多现有的中小型 bash 脚本。

我从下面给出的 bash 脚本开始(添加了一些注释)。我手动将其转换为 Python(如下所示)。请指出我的 Python 哪里可以改进或者变得更简洁。

#!/bin/bash

while IFS= read -r line;
do
  echo $line | grep '^Path=' >/dev/null 2>&1
  if [[ $? -eq 0 ]]; then \
    path=~/.mozilla/firefox/$(echo $line | sed 's/^Path=//')/user.js; #open the user.js file for each profile
    if [[ -f ${path} ]]; then \
      echo "Processing: path: ${path}";
      grep 'browser.ctrlTab.sortByRecentlyUsed' ${path} >/dev/null 2>&1 #check if this property already exists
      if [ $? -ne 0 ]; then \
        echo 'user_pref("browser.ctrlTab.sortByRecentlyUsed", true);' >> ${path}; #did not exist, so append it to end of file
      else
        sed -i 's/browser.ctrlTab.sortByRecentlyUsed",.*false/browser.ctrlTab.sortByRecentlyUsed", true/' ${path} #did exist, so change it to desired value if needed
      fi
      echo "updated ctrlTab.sortByRecentlyUsed for $path"

      grep 'browser.tabs.loadBookmarksInTabs' ${path} >/dev/null 2>&1
      if [ $? -ne 0 ]; then \
        echo 'user_pref("browser.tabs.loadBookmarksInTabs", false);' >> ${path};
      else
        sed -i 's/browser.tabs.loadBookmarksInTabs",.*true/browser.tabs.loadBookmarksInTabs", false/' ${path}
      fi
      echo "updated loadBookmarksInTabs for $path"

    fi
  fi
done < ~/.mozilla/firefox/profiles.ini #read this file to find the path to all profiles

我现在有了一个可用的 Python 解决方案,但它似乎比我预期的要复杂得多。我的目标是能够针对这种情况编写简短而快速的解决方案。目前我不期望编写大型 Python 程序。我确实希望在学得足够多后能够广泛使用 xonsh。显然,我可以摆脱我为学习而包含的打印语句。除此之外,如何改进或缩短下面所示的解决方案?

特别是,我本来打算使用皮塞德和Python的文件输入但我无法用这些实现可行的解决方案。

import sys
from pathlib import Path
import re

trgt_file='user.js'
myuser='mountainx'
base_path = Path('/home/' myuser '/.mozilla/firefox')
if not base_path.is_dir():
  print("ERROR:", base_path, "does not exist.")
  # exit()
else:
  print("OK: processing", base_path)

ini_path = Path(base_path / 'profiles.ini')
if not ini_path.is_file():
  print("ERROR:", ini_path, "cannot be opened.")
  # exit()
else:
  print("OK: opening", ini_path)

match_ctrltab = False
match_bookmark_found = False
pro_path_re = re.compile(r'^Path=(\w+)$')
ctrltab_sort_regex = re.compile(r'^/*?user_pref\("browser\.ctrlTab\.sortByRecentlyUsed.*$', re.M)
ctrltab_sort_repls = 'user_pref("browser.ctrlTab.sortByRecentlyUsed", true);'
bookmark_open_regex = re.compile(r'^/*?user_pref\("browser\.tabs\.loadBookmarksInTabs.*$', re.M)
bookmark_open_repls = 'user_pref("browser.tabs.loadBookmarksInTabs", false);'
with open(ini_path, "r") as profiles_ini:
  for any_line in profiles_ini:
    m_path = pro_path_re.match(any_line)
    if not m_path is None:
      p_path = m_path.group(1)
      print("p_path:", p_path)
      profile_path = Path(base_path / p_path)
      print("profile_path:", profile_path)
      if profile_path.is_dir():
        print("The profile path is", profile_path)
        user_js_path = Path(profile_path / trgt_file)
        if Path(user_js_path).is_file():
          print("OK: valid file:", user_js_path)
          with open(user_js_path, 'r+') as file_userjs:
            #read the file contents
            file_contents = file_userjs.read()
            match_ctrltab = ctrltab_sort_regex.search(file_contents)
            if match_ctrltab is None:
              file_contents = file_contents + '\n' + ctrltab_sort_repls
              print('No match: added line to end of file contents:', ctrltab_sort_repls)
            else:
              file_contents = ctrltab_sort_regex.sub(ctrltab_sort_repls, file_contents)
              print('Match found. Replaced line in file for ctrltab_sort')

            match_bookmark = bookmark_open_regex.search(file_contents)
            if match_bookmark is None:
              file_contents = file_contents + '\n' + bookmark_open_repls
              print('No match: added line to end of file contents:', bookmark_open_repls)
            else:
              file_contents = bookmark_open_regex.sub(bookmark_open_repls, file_contents)
              print('Match found. Replaced line for bookmark_open_regex')
            file_userjs.seek(0)
            file_userjs.truncate()
            file_userjs.write(file_contents)
        else:
          print("SKIPPED: invalid file:", user_js_path)

这是我正在测试的一些日期。一般解决方案应该适用于任何 Firefox user.js 或 prefs.js 文件。

file_contents = """
user_pref("media.gmp-gmpopenh264.abi", "x86_64-gcc3");
user_pref("media.gmp-gmpopenh264.autoupdate", false);
user_pref("media.gmp-gmpopenh264.enabled", false);
user_pref("media.gmp-gmpopenh264.lastUpdate", 1571947201);
user_pref("media.gmp-gmpopenh264.version", "1.8.1");
user_pref("browser.ctrlTab.sortByRecentlyUsed",false);
//user_pref("browser.ctrlTab.sortByRecentlyUsed", true);"""

答案1

这是迄今为止我自己想出的最好的。

我编写了两个函数并将它们保存在名为 modtest 的目录中(并将文件保存为 ffutils.py)。
touch modtest/__init__.py
https://stackoverflow.com/a/33770042了解更多相关信息。

import sys
from pathlib import Path
import re

def find_profile_dirs(user=None, debug=False):
  profiles = []
  if user is None:
    base_path = Path('~/.mozilla/firefox').expanduser()
  else:
    base_path = Path('/home') / user / '.mozilla/firefox'
  if not base_path.is_dir():
    print("ERROR:", base_path, "does not exist.")
  elif debug:
    print("OK: processing", base_path)
  ini_path = Path(base_path / 'profiles.ini')
  if not ini_path.is_file():
    print("ERROR:", ini_path, "cannot be opened.")
  elif debug:
    print("OK: opening", ini_path)
  pro_path_re = re.compile(r'^Path=(\w+)$')
  with open(ini_path, "r") as profiles_ini:
    for any_line in profiles_ini:
      m_path = pro_path_re.match(any_line)
      if not m_path is None:
        p_path = m_path.group(1)
        if debug:
          print("p_path:", p_path)
        profile_path = Path(base_path / p_path)
        if debug:
          print("profile_path:", profile_path)
        if profile_path.is_dir():
          profiles.append(profile_path)
          print("The profile path is", profile_path)
  return profiles


# profiles_paths is a list of Paths of all Firefox profiles to process
def process_userjs(searchExp, replaceExp, profiles_paths, debug=False):
  match_result = None
  search_regex = re.compile(searchExp, re.M)

  trgt_file='user.js'
  for profile_path in profiles_paths:
    user_js_path = Path(profile_path / trgt_file)
    if Path(user_js_path).is_file():
      if debug:
        print("OK: valid file:", user_js_path)
      with open(user_js_path, 'r+') as file_userjs:
        file_contents = file_userjs.read()
        match_result = search_regex.search(file_contents)
        if match_result is None:
          file_contents = file_contents + '\n' + replaceExp
          if debug:
            print('No match: added new line to end of file contents:', replaceExp)
        else:
          file_contents = search_regex.sub(replaceExp, file_contents)
          if debug:
            print('Match found. Modified existing line in file.')

        file_userjs.seek(0)
        file_userjs.truncate()
        file_userjs.write(file_contents)
    elif debug:
      print("SKIPPED: invalid file:", user_js_path)

然后我使用了这样的函数:

import sys
sys.path = ['/path/to/parent/of/modtest'] + sys.path # if needed
from modtest import ffutils

my_profiles = ffutils.find_profile_dirs()

srchexp = r'^/*?user_pref\("browser\.ctrlTab\.sortByRecentlyUsed.*$'
replexp = 'user_pref("browser.ctrlTab.sortByRecentlyUsed", true);'
ffutils.process_userjs(srchexp, replexp, my_profiles, True)

当然,我可以用其他搜索和替换字符串重复它。

我确信还有很多方法可以改进这一点。我会接受其他答案,但我将自己的答案放在这里,以防没有其他答案。

我的代码中有一些假设。一大问题是它假设所有 Firefox 配置文件路径都是相对的。如果这不是一个有效的假设,则需要对profiles.ini 进行更多处理。

相关内容