-2

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

Why this line doesn't work?

if I do

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

It works, I tried with "" without " and with ' in my script and it seems like it's not getting piped to grep. I don't know why? I'm using bash.

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

I want to grab only .por. or .eng in a file

3
  • Are you literally running that first line as-is? Are you sure that the FILENAME variable isn't empty?
    – igal
    Commented Nov 6, 2017 at 12:09
  • 2
    In what way does it not work? Is $name empty? How do you check it? Do you get an error?, What do you get if you replace grep -E ... with sed -n l? What do you expect to achieve with that command? What about doing case $FILENAME in (*.eng.* | *.por.* | *.pt-BR.*) ...; esac? Commented Nov 6, 2017 at 12:29
  • @StéphaneChazelas no error, it's just printed the entire variable. Yes $name is empty and I set $FILENAME before it with FILENAME="Test (2013) [HDTV-720p].bluray.1080p.por.mkv"
    – Freedo
    Commented Nov 6, 2017 at 12:30

2 Answers 2

3

grep is the tool to print (whole) lines matching a pattern. It's not appropriate to extract parts of a string (though some grep implementations have -o<n> or -o options that can be used in some cases for that).

Here, you can use expr:

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

(for foo.por.eng.bar, gives priority to eng over por over pt-PT).

Some expr implementations like GNU expr also support:

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

(here returns the rightmost occurrence if there are several in the filename)

With GNU grep or compatible:

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

(returns first occurrence, replace head with tail for last)

Or you could use your shell's case construct and not run any command at all:

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

With bash:

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

(first occurrence. With zsh, replace BASH_REMATCH with match)

7
  • Why it's not appropriated if it seems everyone uses it?
    – Freedo
    Commented Nov 6, 2017 at 12:37
  • one point is that it will not filter correctly, it will catch literals too like "[HDTV-720p].bluray.1080p.(eng|por|pt-BR).mkv" Commented Nov 6, 2017 at 12:43
  • thanks! expr seems also much easier to learn and use, and it worked both in situations where I had "eng" words in my filename but the a .por.srt file. It had a 100% success in those kind of tests so thank you so much.
    – Freedo
    Commented Nov 6, 2017 at 12:45
  • what if I wanted to apply this to a variable that is a directory?
    – Freedo
    Commented Nov 6, 2017 at 13:07
  • @Freedo, not sure what you mean, that's just string manipulation, it doesn't care whether that string is a path to a directory or any other type of file. Commented Nov 6, 2017 at 13:13
1

Assuming the file names are like Some name.por.mkv, with the final extension fixed, you could use the POSIX shell string operations, too:

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

Here, ${var%.mkv} removes the trailing .mkv, and ${var##*.} removes everything up to the (now) last dot. You could change the first expansion to handle other extensions by changing .mkv to just .*.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .