2

This question already has an answer here:

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

marked as duplicate by Jeff Schaller, Sparhawk, Isaac, heemayl, Mr Shunz Jan 28 at 9:50

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    Just use rename. If the Perl version, it's just rename 's/.ts$/.mkv' *. – Sparhawk Jan 28 at 1:38
  • I want to save the renamed file to a variable to pass in another command in the script (input name -> output name). The examples are for renaming them in the directory – NasKar Jan 28 at 3:22
  • 1
    Please edit your question to include this information. – Sparhawk Jan 28 at 3:39
  • Are your files named with .ts actually Matroska files? Why are they all misnamed? – jamesdlin Jan 28 at 5:57
4

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"
  • the 1st option works the second give file.mkv/*.mkv – NasKar Jan 29 at 3:16
  • If the loop is applied only to files in "${1}"/*.ts I don't see how a .mkv file gets in the list. @NasKar – Isaac Jan 29 at 6:28
2
find . -maxdepth 1 -type f -name '*.ts' -exec rename .ts .mkv {} "+"

Run this in the directory containing the .ts files.

1
#!/bin/sh
for file in "${1}"/*.ts; do
   mv "${file}" "$(basename "${file}").mkv"
done
0

rename is what you're looking for :

rename '.ts' '.mkv' "${1}/*.ts"
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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.