【问题标题】:Sed problem creating correct regular expression创建正确正则表达式的 Sed 问题
【发布时间】:2011-01-19 05:25:12
【问题描述】:

一个非常基本的问题,但我似乎无法在 stackoverflow 或在线其他地方找到真正解决问题的答案。

我正在编写一个简单的 bash 脚本来批处理一堆文件。该脚本由目录列表提供,然后单独处理它们。不幸的是,每个文件名的格式可能会有所不同,这就是我遇到麻烦的地方。下面是我正在使用的文件名类型和正在使用的脚本的示例。

附:我确信也可能有某种方法可以使用 awk(或任何数量的 unix 工具,但现在我专注于 sed)。

提前致谢:

文件:

/home/acct/Foo-Bar.fl
/home/acct/Foo-1.1.fl
/home/acct/Cat-3.4-500.fl
/home/acct/DOG-BEAR-4.4-1.1.fl
/home/acct/DOG-BEAR-4.4-UPDATED.fl

我正在尝试从每一行中提取完整路径、文件名、版本号和文件前缀。以下是我最近的尝试:

DIR_PATH="/home/acct/
for i in `find ${DIR_PATH}`;
do
FILEPATH="$i"
FILENAME=`echo $i | sed -e "s#${DIR_PATH}##g"`
FILEPREFIX=`echo $FILENAME | sed -e "s/\(.*\)-[0-9]\+.*/\1/g"`
FILEVERSION=`echo $FILENAME | sed -e "s/.*-\([0-9]\+.*\)\.fl/\1/g`
echo "$DIR_PATH"
echo "$FILE_PATH"
echo "$FILENAME"
echo "$FILEPREFIX"
echo "$FILEVERSION"
    #do something with this file now that I know what is going on with it
done

在处理以“破折号”分隔的版本号和没有版本号的文件时,问题就来了。我想我已经解决了复杂版本号的所有问题,但仍在努力解决根本不存在版本号的情况。

我想我需要做一些 or 或 type 表达式(或者有第二个 sed 语句来做另一遍),但我不确定如何格式化它。

更新:

根据 Axel 的评论,通过使用 basename 而不是尝试匹配路径,可以更轻松地确定文件名。此外,下面的答案涉及将文件名与扩展名分开,这也是我认为值得纳入的更改。

我会将脚本更新为类似于以下内容的更改:

FILEPATH="$i"
FILENAME=`basename $i`
FILENAMENOSUFFIX=`echo $FILENAME | sed -e "s/\(.*\)\..*/\1/g"`
FILEPREFIX=`echo $FILENAME | sed -e "s/\(.*\)-[0-9]\+.*/\1/g"`

【问题讨论】:

  • 有些人在遇到问题时会想“我知道,我会使用正则表达式”。现在他们有两个问题。 ——杰米·扎温斯基
  • 至少对于文件名,您应该使用 FILENAME=basename $i。它可以正常工作(即使名称包含哈希“#”...
  • Axel,这很好(之前没有使用过 basename)。这是从文件名中剥离目录信息的一种更好的技术。重大帮助!

标签: regex bash sed


【解决方案1】:

Pure Bash(find 除外):

shopt -s extglob
while read -r file
do
    dir=${file%/*}
    name=${file##*/}
    noext=${name/%.fl}
    pre=${noext%%-@([0-9])*}
    ver=${noext/#$pre-}
    [[ ${#ver} == ${#noext} ]] && ver=
    echo "Dir: $dir, Name: $name, Noext: $noext"
    echo "   Pre: $pre, Ver: $ver"
done < <(find "$dir" -type f)

使用您的示例文件名输出:

Dir: /home/acct, Name: Foo-Bar.fl, Noext: Foo-Bar
   Pre: Foo-Bar, Ver: 
Dir: /home/acct, Name: Foo-1.1.fl, Noext: Foo-1.1
   Pre: Foo, Ver: 1.1
Dir: /home/acct, Name: Cat-3.4-500.fl, Noext: Cat-3.4-500
   Pre: Cat, Ver: 3.4-500
Dir: /home/acct, Name: DOG-BEAR-4.4-1.1.fl, Noext: DOG-BEAR-4.4-1.1
   Pre: DOG-BEAR, Ver: 4.4-1.1
Dir: /home/acct, Name: DOG-BEAR-4.4-UPDATED.fl, Noext: DOG-BEAR-4.4-UPDATED
   Pre: DOG-BEAR, Ver: 4.4-UPDATED

【讨论】:

  • 丹尼斯,感谢您的回复。虽然比我想要的更多 bash,但这是很容易理解和理解的。我也喜欢将无扩展版本作为中间步骤的想法。然后,您可以进行简单的比较以确定是否存在版本并采取相应措施。虽然这是一个非常简单的示例,但您的答案很容易理解,并为未来的迭代提供了基础。谢谢!
【解决方案2】:
find . -type file | sed 's!\(.*\)/\([^/0-9]*\)-\([0-9][^/]*\)\.\([^./]*\)$!\0 \1 \2 \3 \4!'

这假设每个文件都是这样设置的:{base}/{prefix}-{version-starts-with-number}.{extension}

【讨论】:

  • 乔恩,这看起来确实可行,谢谢,但从最初的查看来看,它有点难以阅读和解析。我不确定您的命令是否解决了这个问题,但并非所有文件都可能有 {version-starts-with-number} 部分,这就是导致上述问题的原因。
猜你喜欢
  • 2016-11-02
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 2018-03-20
  • 2018-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多