shell 解析文件名以获得一致的python包名

j13ufse2  于 2023-11-21  发布在  Shell
关注(0)|答案(4)|浏览(169)

需要一些脚本帮助。这里是问题。我有一套python包(文件)

beautifulsoup4-4.12.2-py3-none-any.whl
certifi-2023.7.22-py3-none-any.whl
charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
google-3.0.0-py2.py3-none-any.whl
idna-3.4-py3-none-any.whl
protobuf3-0.2.1.tar.gz
protobuf-3.19.6-py2.py3-none-any.whl
proton-0.9.1.tar.gz
python-qpid-proton-0.38.0.tar.gz
redis-4.5.5-py3-none-any.whl
requests-2.31.0-py3-none-any.whl
robotframework-6.1.1-py3-none-any.whl
robotframework_requests-0.9.1-py3-none-any.whl
robotframework-run-keyword-async-1.0.8.tar.gz
soupsieve-2.5-py3-none-any.whl
urllib3-2.0.7-py3-none-any.whl

字符串
我需要解析每个文件名以获取软件包名称及其版本。我有一些工作,而其他人失败。基本上上面的列表应该找到每个名称和版本。

beautifulsoup4                    4.12.2
certifi                           2023.7.22
charset-normalizer                3.3.1
google                            3.0.0
idna                              3.4
protobuf3                         0.2.1
protobuf                          3.19.6
proton                            0.9.1
python-qpid-proton                0.38.0
redis                             4.5.5
requests                          2.31.0
robotframework                    6.1.1
robotframework-requests           0.9.1
robotframework-run-keyword-async  1.0.8
soupsieve                         2.5
urllib3                           2.0.7


我已经尝试过cut,grep,sed,和awk来实现这个功能,但是名字中出现的数字,多位数版本,模式的不一致,会导致一个或另一个方法失败。你也会注意到charset和robotframework-requests更改为a -,但是我希望这些情况不太常见,当它发生时,我可以解决这个问题。
这是我当前的脚本逻辑(fullName是上面列出的文件名),但如果对certifici,charset-normalizer,idna,soupsieve和robotframework-requests失败,

version=`echo "$fullName" | sed -nre 's/^[^0-9]*(([0-9]+\.)*[0-9]+).*/\1/p'`
artifactId=`echo "$fullName" | sed -r "s/-${version}.*//g"`


特别是对于当前脚本,对于那些不工作的脚本,构建工件和版本为:

beautifulsoup4                  4
protobuf3-0.2.1.tar.gz          3
urllib3-2.0.7-py3-none-any.whl  3


如果任何人有一个很好的方法来解析artifactId/版本与regex或任何其他bash脚本的方法,我愿意尝试任何东西。
谢谢

57hvy0tb

57hvy0tb1#

如果输入是存储在文件中或来自管道的名称列表,那么sedawk解决方案将是更好的方法,因为这将比shell循环阅读输入更有效(参见why-is-using-a-shell-loop-to-process-text-considered-bad-practice),但假设输入实际上只是存储在变量中的1个字符串,bash内置是更好的方法,因为这比生成一个子shell在管道中调用echo+sed更有效。
因此,在第一个捕获组中将_ s转换为- s后,要对名为fullName s的变量的内容进行regexp-match,并将所需的部分保存到名为version的变量中,只需使用bash内置程序即可:

[[ $fullName =~ ^(.*)-([0-9]+(\.[0-9]+)*) ]] &&
    printf -v version '%s\t%s\n' "${BASH_REMATCH[1]//_/-}" "${BASH_REMATCH[2]}"

字符串
使用shell循环从您提供的示例输入填充fullName,以便我们可以演示(同样,您不会编写shell循环来操作文本):

$ while IFS= read -r fullName; do
    [[ $fullName =~ ^(.*)-([0-9]+(\.[0-9]+)*) ]] &&
        printf '%s\t%s\n' "${BASH_REMATCH[1]//_/-}" "${BASH_REMATCH[2]}"
  done < file  | column -t
beautifulsoup4                    4.12.2
certifi                           2023.7.22
charset-normalizer                3.3.1
google                            3.0.0
idna                              3.4
protobuf3                         0.2.1
protobuf                          3.19.6
proton                            0.9.1
python-qpid-proton                0.38.0
redis                             4.5.5
requests                          2.31.0
robotframework                    6.1.1
robotframework-requests           0.9.1
robotframework-run-keyword-async  1.0.8
soupsieve                         2.5
urllib3                           2.0.7


请参阅:

xa9qqrwz

xa9qqrwz2#

使用sed,您可以在最后一次出现-之后使用2个捕获组和捕获和编号格式,然后是-.
如果版本中必须至少有一个点,则可以将(\.[0-9]+)*更改为(\.[0-9]+)+

sed -E 's/^(.*)-([0-9]+(\.[0-9]+)*)[.-].*/\1 \2/' file | column -t

字符串
输出

beautifulsoup4                    4.12.2
certifi                           2023.7.22
charset_normalizer                3.3.1
google                            3.0.0
idna                              3.4
protobuf3                         0.2.1
protobuf                          3.19.6
proton                            0.9.1
python-qpid-proton                0.38.0
redis                             4.5.5
requests                          2.31.0
robotframework                    6.1.1
robotframework_requests           0.9.1
robotframework-run-keyword-async  1.0.8
soupsieve                         2.5
urllib3                           2.0.7

oiopk7p5

oiopk7p53#

如果你只有一个Input_file,并且你想从它里面得到值,那么试试下面的方法。用GNU awk编写和测试。仅用显示的示例编写和测试。

awk '
match($0,/^(.*)-([0-9]+(\.[0-9]+)*)[.-].*/,arr){
  print arr[1]"\t"arr[2]
}
' packagesFile.txt  | column -t

字符串

tjvv9vkg

tjvv9vkg4#

有什么想法。
如果您可以使用外部python包,您可以使用wheel-filename作为wheel(*.whl)文件,请首先通过以下方式安装它:

python3 -m pip install wheel-filename

字符串
那么您可以按照以下方式使用它,假设您有list.txt,如下所示

beautifulsoup4-4.12.2-py3-none-any.whl
certifi-2023.7.22-py3-none-any.whl
charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
google-3.0.0-py2.py3-none-any.whl
idna-3.4-py3-none-any.whl
protobuf3-0.2.1.tar.gz
protobuf-3.19.6-py2.py3-none-any.whl
proton-0.9.1.tar.gz
python-qpid-proton-0.38.0.tar.gz
redis-4.5.5-py3-none-any.whl
requests-2.31.0-py3-none-any.whl
robotframework-6.1.1-py3-none-any.whl
robotframework_requests-0.9.1-py3-none-any.whl
robotframework-run-keyword-async-1.0.8.tar.gz
soupsieve-2.5-py3-none-any.whl
urllib3-2.0.7-py3-none-any.whl


使用以下内容创建nameparser.py

from wheel_filename import parse_wheel_filename
with open("list.txt", "r") as f:
    filenames = [i.rstrip() for i in f.readlines()]  # strip trailing newlines
for fname in filenames:
    if fname.endswith("whl"):
        pwf = parse_wheel_filename(fname)
        print(pwf.project, pwf.version)
    else:
        print("Non-wheel file", fname)


然后执行python3 nameparser.py以获得以下输出

beautifulsoup4 4.12.2
certifi 2023.7.22
charset_normalizer 3.3.1
google 3.0.0
idna 3.4
Non-wheel file protobuf3-0.2.1.tar.gz
protobuf 3.19.6
Non-wheel file proton-0.9.1.tar.gz
Non-wheel file python-qpid-proton-0.38.0.tar.gz
redis 4.5.5
requests 2.31.0
robotframework 6.1.1
robotframework_requests 0.9.1
Non-wheel file robotframework-run-keyword-async-1.0.8.tar.gz
soupsieve 2.5
urllib3 2.0.7


如果你想知道更多关于命名轮子文件阅读PEP 427

相关问题