Changing the name of a file based on a part of its original name that are between the first two instances of a character

I am trying to change the names of my files based on the string between the first two instances of "|". This is what my problem looks like:

>1234|interest1|randomstuff1.txt

>5678|interest2|randomstuff2.txt

>9101112|interest3|randomstuff3|trickything.txt

And my desired output is:

interest1.txt

interest2.txt

interest3.txt

I’ve tried some stuff using regex and variables in bash but I wasn’t able to achieve the results that I wanted.

Thank you very much!

Asked By: Fernando

||

This script assumes that you want to process all files that contain at least two | characters and end with .txt. The example file names in the question would also match *interest*.txt. If your requirement is different, please, clarify this in the question.

If the output is what you expect, remove the echo before mv to actually rename the files. The comments # ... are only to explain the code and can be omitted.

for f in *|*|*.txt
do
    n="${f#*|}"  # remove leading shortest string matching *|
    n="${n%%|*}" # remove trailing longest string matching |*
    echo mv "$f" "$n".txt
done
Answered By: Bodo

I’ve assumed that we’re interested in files starting with >, containing (at least) two of your delimiter symbols (|) and ending with .txt:

Example

# Preparation
touch '>1234|interest1|randomstuff1.txt' '>5678|interest2|randomstuff2.txt' '>9101112|interest3|randomstuff3|trickything.txt'

# Process
for f in '>'*'|'*'|'*.txt
do
    x="${f#*|}"                      # Remove from start until first found '|'
    x="${x%%|*}.txt"                 # Remove from first found `|` to end

    printf "%s -> %sn" "$f" "$x"    # Show what would happen
    # mv -f "$f" "$x"                # Do it (if uncommented)
done

Output (without mv)

>1234|interest1|randomstuff1.txt -> interest1.txt
>5678|interest2|randomstuff2.txt -> interest2.txt
>9101112|interest3|randomstuff3|trickything.txt -> interest3.txt

Uncomment the mv command to move the files. Note that if you have duplicate target names the last one processed will be the one that remains.

Answered By: roaima

If you have perl-rename (called rename on many systems), you can do:

$ rename -n 's/.*?|(.+?)|.*/$1.txt/' *txt 
>1234|interest1|randomstuff1.txt -> interest1.txt
>5678|interest2|randomstuff2.txt -> interest2.txt
>9101112|interest3|randomstuff3|trickything.txt -> interest3.txt

If the output looks like what you want, run the command again without the -n to actually rename the files.

Answered By: terdon

Using the Perl-based rename utility, rename all files whose names match the pattern *interest*.txt. Each file is renamed by splitting the original name on the pipe symbols and then using the second resulting field with .txt added to the end:

rename -n -v '$_ = (split /|/)[1] . ".txt"' *interest*.txt

Remove the -n option when you have made sure that the command outputs the correct new names.

Testing on the names given in the question:

$ ls -1
>1234|interest1|randomstuff1.txt
>5678|interest2|randomstuff2.txt
>9101112|interest3|randomstuff3|trickything.txt
$ rename -v '$_ = (split /|/)[1] . ".txt"' *interest*.txt
>1234|interest1|randomstuff1.txt renamed as interest1.txt
>5678|interest2|randomstuff2.txt renamed as interest2.txt
>9101112|interest3|randomstuff3|trickything.txt renamed as interest3.txt
$ ls -1
interest1.txt
interest2.txt
interest3.txt
Answered By: Kusalananda