Код работает в терминале, но не в скрипте для переименования (манипулирует именами файлов с пробелами)

Я хочу узнать больше, поэтому я пытался писать больше, чем просто используя терминал. Я знаю rename, и я могу переименовать файлы изображений с помощью rename 's/ /_/g' *.jpg, но когда я пишу его в сценарии оболочки, чтобы указать на каталог:

DIRECTORY="/foo/bar"

for imgfile in $(find $DIRECTORY -type f -name \*.jpg); do
    echo 'replacing whitespace in' $(basename $imgfile)
    rename -f 's/ /_/g' *.jpg 
done

он не работает, и терминал примет файл (пример: 1234 abcd.jpg) и эхо abcd.jpg. Так, где я иду не так?

3
задан 20 November 2013 в 04:04

2 ответа

Пробелы в именах файлов являются злыми.

Я вижу три проблемы со сценарием:

  1. при выполнении for... цикл, у Вас будет два различных значения при нахождении файла с пространством. т.е. если у Вас есть файлы "file1 1.jpg" и "file2 2.jpg" и Вы делаете:

    for i in $(find . -type f -name \*.jpg); do 
       echo $i
    done
    

    Вы будете иметь

    ./file1 
    1.jpg
    ./file2
    2.jpg
    

    потому что оболочка повреждает аргумент в пробелах. Вывод $(find ...) команда будет

    ./file1 1.jpg 
    ./file2 2.jpg 
    

    Которые являются четырьмя словами для команды for быть присвоенным в $i ---по умолчанию оболочка рассматривает пробелы и новые строки таким же образом при расширении.

    Можно обойти это изменение символа IFS.

    Ваша первая строка могла быть похожей:

    IFS=$'\n' find $DIRECTORY -type f -name \*.jpg | while read -r imgfile; do
    
  2. Вы питаетесь для цикла с единственным именем файла, таким образом, необходимо сказать:

    rename -f 's/ /_/g' "$imgfile"
    

    иначе *.jpg расширен в текущем каталоге, а не в $DIRECTORY (и отметьте кавычки---, учитывая, что $imgfile движение должно иметь пробелы в нем).

  3. даже затем, если $DIRECTORY имеет некоторый компонент контура с пробелами в нем, переименовывание перестанет работать (будут промежуточные каталоги, которые не существуют).

  4. предложение (сохраняющий это простой):

    DIRECTORY="/foo/bar"
    cd $DIRECTORY
    rename -f 's/ /_/g' *.jpg
    

    не делает то, что Вы хотите?

Добавленный: мой сценарий (созданный давным-давно, когда было нет rename в Unix), этот---, он удалит пробелы и вкладку во всех файлах в текущем dir, которые имеют их на имя:

# 
ls -1  | grep -E " |\t" | while read i; do
    a=`echo $i | tr " \t" "__"`
    mv -v "$i" $a
done

Добавленный ++: эта ссылка я нашел исследование этого ответа, превосходна.

5
ответ дан 20 November 2013 в 04:04

Лучший способ проанализировать результат find пустым указателем, оконечным вывод с -print0

#!/bin/bash

while IFS= read -d '' -r; do
    rename -f "s/ /_/g" "$REPLY"
    if [[ ! -f $REPLY ]]; then
        echo "Renaming file: $(basename "$REPLY")"
    fi
done < <(find -type f -name '*.jpg' -print0)

(Можно справиться без цикла).

$ find -type f -name '*.jpg' \
    -exec bash -c 'rename -f "s/ /_/g" "$1"; \
    [[ -f $1 ]] || echo "Renaming file: $(basename "$1")"' _ '{}' \;
0
ответ дан 17 November 2019 в 10:01

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

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