Rename all the files in .ts files in a directory My echo command works but not if I try to make it a new variable.
#!/bin/sh
for file in "${1}"/*.ts; do
echo ${file} | sed -e 's|.ts|.mkv|'
new_name=${file} | sed -e 's|.ts|.mkv|'
done
Rename all the files in .ts files in a directory My echo command works but not if I try to make it a new variable.
#!/bin/sh
for file in "${1}"/*.ts; do
echo ${file} | sed -e 's|.ts|.mkv|'
new_name=${file} | sed -e 's|.ts|.mkv|'
done
The simplest solution would be to tell you to change the assignment to:
new_name=$( echo ${file} | sed -e 's|.ts|.mkv|' )
But a better solution would be to do:
new_name="${file%.ts}.mkv"
"${1}"/*.ts
I don't see how a .mkv
file gets in the list. @NasKar
–
Jan 29 '19 at 06:28
find . -maxdepth 1 -type f -name '*.ts' -exec rename .ts .mkv {} "+"
Run this in the directory containing the .ts
files.
By using $file
unquoted in your code, you invite the shell to split its contents into words based on the value of $IFS
(space, tab and newline by default). Those words would then undergo filename expansion if they contained any globbing patterns.
By using echo
, you would possibly also expand backslash sequences like \n
and \t
depending on what shell options happened to be set (xpg_echo
).
Your first sed
command would replace any character followed by ts
in the filename with .mkv
. This means that the filename bats.ts
would be changed to b.mkv.ts
.
The second line in the loop is nonsensical, as it takes the output of an assignment and passes it to sed
over a pipe.
Assigning the output of a command to a variable is done with command substitutions:
variable=$( some_command )
#!/bin/sh
for name in "$1"/*.ts; do
mv -i "$name" "${name%.ts}.mkv"
done
This would loop over all files having a filename suffix of .ts
in the directory given by "$1"
. Each file would be renamed to the same name, but with the .ts
filename suffix removed and the .mkv
suffix inserted at the end of the filename.
The variable substitution ${variable%pattern}
would remove the shortest suffix in $variable
that matches pattern
. This would work even if the filename happened to contain embedded newlines.
By using mv -i
we hopefully prevent the function from accidentally overwriting existing files. Another way to do that would be to do something like
#!/bin/sh
for name in "$1"/*.ts; do
newname=${name%.ts}.mkv
if [ ! -e "$newname" ]; then
mv "$name" "$newname"
else
printf 'Name "%s" is already taken\n' "$newname" >&2
fi
done
In addition to this test, you may actually want to check whether $name
exists to start with. If the pattern "$1"/.*ts
does not match any filenames, then it would by default remain unexpanded. We can catch that with
#!/bin/sh
for name in "$1"/*.ts; do
[ ! -e "$name" ] && break
newname=${name%.ts}.mkv
if [ ! -e "$newname" ]; then
mv "$name" "$newname"
else
printf 'Name "%s" is already taken\n' "$newname" >&2
fi
done
In the bash
shell, you could use shopt -s nullglob
to make nonmatching patterns expand to nothing instead. In bash
you may also want to use shopt -s dotglob
if you want to additionally match hidden filenames.
#!/bin/sh
for file in "${1}"/*.ts; do
mv "${file}" "$(basename "${file}").mkv"
done
basename
to remove the .ts
suffix, you will need to specify that with an option and provide the suffix to remove explicitly (at least in those implementations of basename
I have come across so far).
– AdminBee
Sep 23 '21 at 08:29
mv
target, so the new files will end up in the current directory.
– Stephen Kitt
Sep 23 '21 at 11:25
rename
. If the Perl version, it's justrename 's/.ts$/.mkv' *
. – Sparhawk Jan 28 '19 at 01:38.ts
actually Matroska files? Why are they all misnamed? – jamesdlin Jan 28 '19 at 05:57