bash 脚本可以从文件名列表中提取名称、版本号和扩展名吗

Can a bash script extract name, version number and extension from a list of filenames

提问人:Simon Bagley 提问时间:10/6/2023 最后编辑:Simon Bagley 更新时间:10/6/2023 访问量:38

问:

我在创建 Bash 脚本时遇到问题,该脚本将从文件名列表中提取应用程序名称、版本号和可能的扩展名,例如:

  1. 应用程序名称-1-v1.2.3.AppImage
  2. 应用名称2-V999.2.31.AppImage
  3. 另一个应用程序-v123.456.789
  4. 然而-另一个-例子-4-V0.0.1.extA

对于上述示例,应用程序名称为:

  1. 应用程序名称-1
  2. 应用名称2
  3. 另一个应用程序
  4. 然而-另一个例子-4

版本号为:

  1. 1.2.3
  2. 999.2.31
  3. 123.456.789
  4. 0.0.1

扩展将是:

  1. “应用图像”
  2. “应用图像”
  3. ""
  4. “extA”

所有文件名的版本号前面都以 v 或 V 开头,但可能有扩展名,也可能没有扩展名。

我尝试了在 Google Bard 的帮助下创建的以下脚本:

#!/bin/bash

# Function to parse a filename and separate out the base name, version number, and extension
function parse_filename() {
    # Get the base name of the file
    basename=${1##*/}

    # Get the extension of the file
    extension=${basename##*.}

  # Remove the extension from the base name
  basename=${basename%.*}

  # Get the version number of the file
  version=${basename##*-}

  # Strip any leading or trailing spaces from the base name and version number
  basename=${basename## }
  basename=${basename%% }
  version=${version## }
  version=${version%% }

  # If the version number is not in the form digits.digits.digits, then set the version number to an empty string
  if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
      version=""
  fi

  # If the version number is empty, then the version number is the extension
  if [[ -z "$version" ]]; then
      version="$extension"
  fi

  # If the base name is empty, then the base name is the filename without the extension
  if [[ -z "$basename" ]]; then
      basename=${1%.*}
  fi
}

echo "Running script: $0"

# Get the list of filenames from the user
filenames=("$@")

# Iterate over the list of filenames and parse each one
for filename in "${filenames[@]}"; do
    echo "Processing filename: $filename"
    # Parse the filename and get the base name, version number, and extension
    parse_filename "$filename"

  # Print the results to the: console
  echo "Base name: $basename"
  echo "Version number: $version"
  echo "Extension: $extension"
  echo
done

但是,这不会产生正确的输出:

Running script: ./filename-parser.sh
Processing filename: name-of-application-1-v1.2.3.AppImage
Base name: name-of-application-1-v1.2.3
Version number: 
Extension: 

Processing filename: app-name2-V999.2.31.AppImage
Base name: app-name2-V999.2.31
Version number: 
Extension: 

Processing filename: another-application-v123.456.789
Base name: another-application-v123.456
Version number: 
Extension: 

Processing filename: yet-another-example-4-V0.0.1.extA
Base name: yet-another-example-4-V0.0.1
Version number: 
Extension: 

这在 bash 脚本中是否可能,或者我是否需要求助于 Python 或其他东西。

字符串 bash shell 解析

评论

0赞 RomanPerekhrest 10/6/2023
您可以让用户将“文件名列表”作为包含它们的文本文件传递吗?
0赞 Simon Bagley 10/6/2023
@RomanPerekhrest 是的,这是一个选项

答:

1赞 Benjamin W. 10/6/2023 #1

您可以使用正则表达式,如下所示:

#!/usr/bin/env bash

files=(
    name-of-application-1-v1.2.3.AppImage
    app-name2-V999.2.31.AppImage
    another-application-v123.456.789
    yet-another-example-4-V0.0.1.extA
)

re='(.*)-[vV](([[:digit:]]+\.){2}[[:digit:]]+)(\.(.*))?'

for file in "${files[@]}"; do
    printf 'Processing: %s\n' "$file"
    [[ $file =~ $re ]]
    printf 'Base name: %s\n' "${BASH_REMATCH[1]}"
    printf 'Version number: %s\n' "${BASH_REMATCH[2]}"
    printf 'Extension: %s\n\n' "${BASH_REMATCH[5]}"
done

评论

0赞 Simon Bagley 10/6/2023
太好了,这很完美。我显然需要学习如何正确使用正则表达式!
1赞 Paul Hodges 10/6/2023 #2

BASH_REMATCH是一个不错的选择,但如果复杂的正则表达式让您头疼,您通常可以使用基于 glob 的标准参数扩展来完成相同的操作。

$: cat tst
#!/bin/bash
while read -r fn; do app=${fn%-[vV][0-9]*}; ext=${fn##*[0-9.]}; ver=${fn%.$ext}; ver=${ver#*-[Vv]};
  printf "Filename: %-40.40s App: %-25.25s Version: %-10.10s Extenssion: %-10.10s\n" "$fn" "$app" "$ver" "$ext"
done < files

P2759474@CORTOPSALBSC7Q9 2023-10-06,10:20:18 /tmp
$: ./tst
Filename: name-of-application-1-v1.2.3.AppImage    App: name-of-application-1     Version: 1.2.3      Extenssion: AppImage
Filename: app-name2-V999.2.31.AppImage             App: app-name2                 Version: 999.2.31   Extenssion: AppImage
Filename: another-application-v123.456.789         App: another-application       Version: 123.456.78 Extenssion:
Filename: yet-another-example-4-V0.0.1.extA        App: yet-another-example-4     Version: 0.0.1      Extenssion: extA

无论哪种情况,您只需要识别和编码您的假设。

我使用了这些: :
dash,V,digit 开始版本(不区分大小写):
扩展名不能有数字
${fn%-[vV][0-9]*}${fn##*[0-9.]}

${fn%.$ext} / ${ver#*-[Vv]}:删除最高版本启动和任何扩展名

任何正则表达式也编码类似的假设,但根据您的品味和技能组合,可能更容易或可能更难阅读。如果文件很多,单个正则表达式解析可能会更快。