Grep 不使用变量,即使带引号

Grep 不使用变量,即使带引号

name=$(echo "$FILENAME" | grep -E '*\.(eng|por|pt-BR)\.*')

为什么这条线不起作用?

如果我做

echo "Test (2013).1080p.por.mkv" | grep -E "*\.(eng|por)\.*"

它有效,我在脚本中尝试使用“”而不使用“和使用',但似乎没有通过管道传输到grep。我不知道为什么?我正在使用bash。

FILENAME="Test (2013).1080p.por.mkv"

我只想抓取.por。或文件中的 .eng

答案1

grep是打印与模式匹配的(整行)行的工具。提取字符串的一部分是不合适的(尽管某些grep实现具有-o<n>-o在某些情况下可以使用的选项)。

在这里,您可以使用expr

name=$(expr " $FILENAME" : '.*\.\(eng\)\.' '|' \
            " $FILENAME" : '.*\.\(por\)\.' '|' \
            " $FILENAME" : '.*\.\(pt-PT\)\.')

(对于foo.por.eng.bar, 优先于over eng)。porpt-PT

一些expr实现(例如 GNU)expr也支持:

name=$(expr " $FILENAME" : '.*\.\(eng\|por\|pt-PT\)\.')

(如果文件名中有多个,则返回最右边的匹配项)

使用 GNUgrep或兼容:

name=$(
  printf '%s\n' "$FILENAME" |
    grep -Po '\.\K(eng|por|pt-PT)(?=\.)' |
    head -n 1
)

(返回第一个出现的位置,替换headtail最后一个出现的位置)

或者您可以使用 shell 的case构造而不运行任何命令:

case $FILENAME in
  (*.por.*) name=por;;
  (*.eng.*) name=eng;;
  (*.pt-PT.*) name=pt-PT;;
esac

bash

re='\.(por|eng|pt-PT)\.'
[[ $FILENAME =~ $re ]]
name=${BASH_REMATCH[1]}

(第一次出现。用zsh,替换BASH_REMATCHmatch

答案2

假设文件名类似于Some name.por.mkv,并且最终扩展名固定,您也可以使用 POSIX shell 字符串操作:

$ echo "$FILENAME"
Test (2013).1080p.por.mkv
$ x=${FILENAME%.mkv}; echo "${x##*.}"
por

在这里,${var%.mkv}删除尾随.mkv,并${var##*.}删除直到(现在)最后一个点的所有内容。您可以通过更改.mkv为仅更改第一个扩展来处理其他扩展 .*

相关内容