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!
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
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.
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.
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