我开始学习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 进行更多处理。