Работа с пространством в ссылках на файлы с помощью bash [duplicate]

У меня проблема. Вот мой сценарий bash для объединения видео с подпрограммами:

#!/bin/bash 

cd /media/ptrknvk/'TOSHIBA EXT'/Shows/My/'Doctor Who'/

url0='DW s11e0'
url1='DW\ s11e'

for(( i=1; i<11; i++ ))
do
    if ! [ $i -gt 9 ]; 
    then
        mkvmerge -o $url0$i.mkv $url0$i.mkv $url0$i.srt
        rm $url0$i.srt
    else
        mkvmerge -o $url1$i.mkv $url1$i.mkv $url1$i.srt
        rm $url1$i.srt
    fi
done

Файл имеет имена, например, «DW s11e05.mkv», и они действительно существуют в каталоге.

И вот результат:

mkvmerge v8.8.0 ('Wind at my back') 64bit
Error: The file 's11e09.mkv' could not be opened for reading: open file error.
rm: cannot remove 'DW': No such file or directory
rm: cannot remove 's11e09.srt': No such file or directory
mkvmerge v8.8.0 ('Wind at my back') 64bit
Error: The file 's11e10.mkv' could not be opened for reading: open file error.
rm: cannot remove 'DW\': No such file or directory
rm: cannot remove 's11e10.srt': No such file or directory

Как видите '\' перед пробелом здесь не работает. Я тоже пробовал использовать эхо, но ничего не изменилось (м.б. я неправильно использовал).

Простите за мой немного нуби-стиль.

5
задан 1 January 2019 в 17:10

2 ответа

Необходимо заключить переменные в кавычки. Это должно сделать то, что Вы хотите:

#!/bin/bash 

cd /media/ptrknvk/'TOSHIBA EXT'/Shows/My/'Doctor Who'/

url0='DW s11e0'
url1='DW s11e'

for(( i=1; i<11; i++ ))
do
    if ! [ $i -gt 9 ]; 
    then
        mkvmerge -o "$url0$i.mkv" "$url0$i.mkv" "$url0$i.srt" &&
        rm "$url0$i.srt"
    else
        mkvmerge -o "$url1$i.mkv" "$url1$i.mkv" "$url1$i.srt" &&
        rm "$url1$i.srt"
    fi
done

Обратите внимание, что я также добавил a && после каждого mkvmerge управляйте так rm только выполнения, если mkvmerge было успешно. Вы не хотите удалять файл подзаголовка, если слияние перестало работать!

Тем не менее, хотя нет абсолютно ничего неправильно с Вашим подходом, я чувствую, что Вы могли сделать его значительной более простой и более изящной оболочкой использования globbing вместо этого:

#!/bin/bash 

for file in "/media/ptrknvk/TOSHIBA EXT/Shows/My/Doctor Who/"DW*mkv; do
  srtFile=${file//.mkv/.srt}
  mkvmerge -o "$file" "$file" "$srtFile" && rm "$srtFile"
done

Вам даже не нужен сценарий для этого. Можно просто выполнить его непосредственно в терминале как один лайнер:

for file in "/media/ptrknvk/TOSHIBA EXT/Shows/My/Doctor Who/"DW*mkv; do
  mkvmerge -o "$file" "$file" "${file//.mkv/.srt}" && rm "${file//.mkv/.srt}";
done
11
ответ дан 23 November 2019 в 08:41

Переменные кавычки для предотвращения разделения слова. Между прочим, двойные кавычки на целой строке предпочтительный стиль.

#!/bin/bash

# Also exit if this fails
cd "/media/ptrknvk/TOSHIBA EXT/Shows/My/Doctor Who/" || exit

url0="DW s11e0"
url1="DW s11e"

for (( i=1; i<11; i++ )); do
    # Also why use "not greater-than" when "less-than-or-equal" exists?
    if [ $i -le 9 ]; then
        # Also you can DRY* out this part with variables.
        url="$url0"
    else
        url="$url1"
    fi
    # Also when concatenating variables, it's clearer to use the "${var}" style. **
    f_mkv="${url}${i}.mkv"
    f_srt="${url}${i}.srt"
    mkvmerge -o "$f_mkv" "$f_mkv" "$f_srt"
    rm "$f_srt"
done

Shellcheck действительно полезен для нахождения проблем как это в сценариях оболочки.

* DRY = не повторяют себя

** Или Вы могли использовать printf -v, но это не большое улучшение в этом случае. Например,

printf -v f_mkv "%s%s.mkv" "$url" $i
6
ответ дан 23 November 2019 в 08:41

Другие вопросы по тегам:

Похожие вопросы: