Hi,
I have several directories with hundreds of files in each.
I must rename each file, create a directory of (almost) the same name, and move the file into that directory.
Here is what I have so far (not much):
#!/bin/bash
for file in /foo/*
do
rename the file so that the last 4 characters before the . are enclosed in braces: mv foobar 2017.ext to foobar (2017).ext
make a directory the same name as the file, minus the . and extension: mkdir foobar (2017)
move the file into that directory: mv foobar (2017).ext to foobar (2017)/foobar (2017).ext
done
I could use some help with the actual commands
Thanks,
Charles
rename file, mkdir, mv file
Forum rules
Topics in this forum are automatically closed 6 months after creation.
Topics in this forum are automatically closed 6 months after creation.
rename file, mkdir, mv file
Last edited by LockBot on Wed Dec 28, 2022 7:16 am, edited 1 time in total.
Reason: Topic automatically closed 6 months after creation. New replies are no longer allowed.
Reason: Topic automatically closed 6 months after creation. New replies are no longer allowed.
Some people make happiness wherever they go, others whenever they go.
Re: rename file, mkdir, mv file
There's a Windows utilitiy called Bulk File Rename. I'm sure that Linux has an equivalent. Google may well be your friend here.
Fully mint Household
Out of my mind - please leave a message
Out of my mind - please leave a message
Re: rename file, mkdir, mv file
But if you insist, something like
Remove the "echo" statements once you're satisfied this does what you want. Note that these kinds of string substitutions are quite sensitive to input format; tweak as necessary with help of
[EDIT] looking a little closer you seem to have specified a space in the input filename; "foobar 2017.ext" rather than "foobar2017.ext". You'd simply remove the space before the opening brace in the above second BASE substitution to compensate -- but that's, then, an example of the mentioned sensitivity.
Code: Select all
for FILE in foo/*; do
[ -f "$FILE" ] || continue
NAME="${FILE%.*}"
BASE="${NAME::-4}"
BASE="$BASE (${NAME#$BASE})"
echo mkdir "$BASE"
echo mv "$FILE" "$BASE/${BASE##*/}${FILE#$NAME}"
done
man bash
, 749g
if not fully right for some of your files. Does work for your example format:Code: Select all
$ for FILE in foo/foobar2017.ext; do NAME=${FILE%.*}; BASE=${NAME::-4}; BASE="$BASE (${NAME#$BASE})"; echo mkdir "$BASE"; echo mv "$FILE" "$BASE/${BASE##*/}${FILE#$NAME}"; done
mkdir foo/foobar (2017)
mv foo/foobar2017.ext foo/foobar (2017)/foobar (2017).ext
Re: rename file, mkdir, mv file
rene,
Works perfect! You don't know how much time and trouble you've saved me. Thank you kindly.
Charles
Works perfect! You don't know how much time and trouble you've saved me. Thank you kindly.
Charles
Some people make happiness wherever they go, others whenever they go.
Re: rename file, mkdir, mv file
Just for fun, in addition to using the cool bash parameter expansion above, I tried it with matching the filename to a regular expression and using BASH_REMATCH to get the parts.
The other method, uses the IFS to split the filename into pieces before putting it back together again to form the new name. I used $'\x20'" to represent the space, so if I look at the code in the future I know I clearly meant it to be a space
I wasn't sure what "enclosed in braces" meant when I saw "foobar (2017).ext". I've always gone by:
( ) parentheses
[ ] brackets (hard "k" sound has hard corners ))
{ } braces
The other method, uses the IFS to split the filename into pieces before putting it back together again to form the new name. I used $'\x20'" to represent the space, so if I look at the code in the future I know I clearly meant it to be a space
I wasn't sure what "enclosed in braces" meant when I saw "foobar (2017).ext". I've always gone by:
( ) parentheses
[ ] brackets (hard "k" sound has hard corners ))
{ } braces
Code: Select all
#!/bin/bash
# Use regular expression to parse file name into required pieces
#
declare -r pf='(' pe=')'
declare -- fname='' parts='' year='' ext='' newname=''
declare -r regexfname='^([^[:blank:]]+[[:blank:]])([[:digit:]]{4})(\.[[:alpha:]]{3})$'
while read -re line; do
[[ "$line" =~ $regexfname ]]
rc=$?
case $rc in
0) fname="${BASH_REMATCH[1]}"
year="${BASH_REMATCH[2]}"
ext="${BASH_REMATCH[3]}"
echo "fname=$fname year=$year ext=$ext"
newname="$fname$pf$year$pe"
echo "newname=$newname"
echo 'do other processing'
;;
1) echo "filename does not match regex [$rc]"
;;
*) echo "regex error [$rc]"
;;
esac
done <<EOF
foobar 2017.ext
EOF
echo; echo
# Use IFS to split words.
# This eats the space and dot (.), so you have to put them back in.
#
#declare -r pf='(' pe=')'
declare -- fname='' parts='' year='' ext='' newname=''
while IFS=$'\x20' read -re fname parts; do
IFS=. read year ext<<<$parts
echo "fname=$fname year=$year ext=$ext"
newname="$fname"$'\x20'"$pf$year$pe"
echo "newname=$newname"
echo 'do other processing'
# mkdir "$newname"
# mv "$fname $parts" "$newname/$newname.$ext"
done <<EOF
foobar 2017.ext
EOF
#######################
# Remove the last 3 lines
#done <<EOF
#foobar 2017.ext
#EOF
# And replace with
# done < <(find foo -maxdepth 1 -type f -printf '%f\n')