I recently got into nautilus scripts, and for the one I'm writing I'd need to extract a substrong from a filename. My problem is that I found tons of methods to extract a substring based on the position of a character, and not any on how to find a given character in my string and extract a substring from or up to this character. cut -f1 -d "delimiter" kinda works, but cut only accepts 1-char delimiter. Maybe awk? expr?

I'm writing in bash I would expect on a file called for example


to be renamed to simply

Any Series S01 E01 VOSTFR.avi`
  • 2
    Edit the question and give example of the input and expected output. – jimmij Dec 24 '15 at 21:10
  • What shell? do its own parameter expansion features not do what you want? – steeldriver Dec 24 '15 at 21:11

With POSIX shells:


If you had written how you would like to use this script, I would be a able to give a more specific answer, however I think the following line might be enough for you to adapt to your needs.

$ echo "abcde" | awk '{print substr($0, index($0, "c"))}'

Just replace the second argument of index to the character you want.


Parameters expansion actually did the trick.

echo ${1%.S??E*}|sed 's/\./ /'

echoes the name of the series and changes potential dots to spaces. Wouldn't work for any series (for example Mr. Robot needs a dot) but, that's close enough already.


You only provided one example. More would be nice!


Which you want broken up into:

  • Any Series
  • S01
  • E01
  • avi

At first glance, this isn't too dissimilar to the problem of RPM package naming, where the first field (name) can contain the delimiter used elsewhere. However, I'm going to assume you have a fixed format field there which you also want to break into two fields.

For this, I would split on season+episode:

IFS=';' episode=( $(echo "$FILENAME"|sed -E 's/(.+)\.(S[0-9]{2})(E[0-9]{2})\.([^\.]+)\..*\.([^\.]+)/\1;\2;\3;\4;\5/') )

I'm setting the delimiter to semicolon for the scope of the assignment, then plugging the output of the regex into a bash array, which will have five fields: ${episode[0]} .. ${episode[4]}

I haven't expanded the episode name field dots to spaces. We could probably do it all in one go, but treating it separately allows you to do stuff like using underscores, or adding complication like looking for double .. in the case of Mr..Robot -> Mr. Robot. Simply:

episode[0]="${episode[0]//./ }"

And more complex, preserving . where it signifies an abbreviation as in "Mr. Robot":

episode[0]="$(echo "${episode[0]}"|sed -E 's/\.([^\.])/ \1/g')"

Lastly, I'd then construct a target filename, using array expansion to print four fields from field #0 delimited by spaces, then a period, then the last field:


Then it's just a matter of passing FILENAME and TARGET to mv, using quotes to be safe:


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.