1

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
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
NasKar
  • 13

5 Answers5

3

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"
2
find . -maxdepth 1 -type f -name '*.ts' -exec rename .ts .mkv {} "+"

Run this in the directory containing the .ts files.

Niko Gambt
  • 433
  • 3
  • 8
0

rename is what you're looking for :

rename '.ts' '.mkv' "${1}/*.ts"
breversa
  • 135
0

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.

Kusalananda
  • 333,661
-1
#!/bin/sh
for file in "${1}"/*.ts; do
   mv "${file}" "$(basename "${file}").mkv"
done
nyet
  • 257
  • 1
    Pleasee not that if you want 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
  • This will also remove the directory from the mv target, so the new files will end up in the current directory. – Stephen Kitt Sep 23 '21 at 11:25