Почему переименование файлов с помощью sed и mv печатает '$'\r'

Я использую Ubuntu на машине с Windows 10. Я пытаюсь переименовать 5 файлов (file1.txt, file2.txt, file3.txt, file4.txt, file5.txt) так, чтобы каждый файл был заменен на Sample#_VoucherID.fastq.gz.

Для этого у меня есть .csv файл, который имеет формат oldfile,newfile и я использую sed следующим образом"

sed 's/^/mv -vi /;s/,/ / /;s/$//' < File-Rename. csv | bash -e

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

Sample#_VoucherID.fastq.gz для каждого файла, я получаю 'Sample#_VoucherID.fastq.gz'$'\r' вместо этого. Почему так происходит? Если я использую mv просто в терминале Ubuntu для переименования файлов, я получаю файлы, переименованные так, как я хочу, без ', $ и \r' до и после имени файла. Если я не использую | bash -e в файле и убираю кавычки, он печатает:

mv -vi file1.txt Sample1_VoucherID.fastq.gz

mv -vi file2.txt Sample2_VoucherID.fastq.gz

mv -vi file3.txt Sample3_VoucherID.fastq.gz

mv -vi file4.txt Sample4_VoucherID.fastq.gz

mv -vi file5.txt Sample5_VoucherID.fastq.gz

однако, на самом деле не выполняется команда mv. Как я могу переименовать свои файлы, не получая этих дополнительных символов?

0
задан 29 June 2021 в 02:11

1 ответ

Это происходит из-за того, что ваш входной файл File-Rename.csv имеет окончания строки CRLF в стиле Windows, а не в стиле Unix LF - $ '\ r' - это способ оболочки для представления символа возврата каретки.

Вы можете «исправить» свою команду, изменив окончательное выражение sed с s / $ // (которое на самом деле ничего не делает - $ в регулярном выражении является утверждение нулевой длины, которое соответствует концу строки, но фактически не использует символ) в s / \ r $ //

В качестве альтернативы, конвертируйте входной файл с помощью dos2unix

ОДНАКО такой подход к переименованию файлов проблематичен - в частности, он не сработает, если старое или новое имя содержит пробелы или определенные специальные символы оболочки - и даже допускает внедрение кода 1 . Вместо этого я бы предложил что-то вроде

while IFS=, read old new; do 
  mv -vi -- "$old" "$new"
done < <(sed 's/\r$//' File-Rename.csv)

или

while IFS=, read old new; do 
  echo mv -vi -- "$old" "${new%$'\r'}"
done < File-Rename.csv

(удалите echo , когда вас устраивают предложенные команды).

Обратите внимание, что этот подход сам по себе не работает для определенных имен, которые допустимы в формате CSV - в частности, тех, которые содержат заключенные в кавычки запятые (например, «foo, bar», baz ).


1 подумайте, что произойдет, если кто-то введет имя файла, например foo; rm * , например

2
ответ дан 28 July 2021 в 11:24

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

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