Как использовать Mv для переименования файлов с конечным пробелом? - PullRequest
1 голос
/ 25 июня 2019

У нас очень большая файловая структура, которая была очень плохо построена.Пути содержат много пробелов, @, пробелов вокруг тире.

Все это размещено на Synology NAS, поэтому у меня нет доступа ко всему массиву обычно включаемых инструментов (например, rename).

Я пытаюсь переименовать файл ANDимена папок с пробелами в начале и в конце.

# Global vars
tstamp=$(date +%Y-%m-%d_%H%M%S)

# Change for separator to newline
IFS=$'\n'

echo "$tstamp - Renaming files with leading space: \n"

for filename in $(find . -type f -name '[[:space:]]*')
do
newFilename=$(echo $filename |sed 's/\/[[:space:]]/\//g')
        echo "original: $filename"
        echo "new     : $newFilename"
        mv -i -v -n $filename $newFilename
        echo "\n"
done

echo "$tstamp - Renaming files with trailing space: \n"

for filename in $(find . -type f -name '*[[:space:]]')
do
newFilename=$(echo $filename |sed 's/[[:space:]]$//g')
        echo "original: $filename"
        echo "new     : $newFilename"
        mv -i -v -n $filename $newFilename
        echo "\n"
done


# A slash "/" in a filename is not possible thus it's not verified
echo "$tstamp - Renaming files with unsupported characters (\ / \" : < > ; | * ?):"

for filename in $(find . -type f -name '*\**' -o -name '*\\*' -o -name '*"*' -o -name '*:*' -o -name '*<*' -o -name '*>*' -o -name '*;*' -o -name '*|*' -o -name '*\?*')
do
newFilename=$(echo $filename |sed 's/\(\\\|"\|:\|<\|>\|;\||\|\*\|\?\)//g')
        echo "original: $filename"
        echo "new     : $newFilename"
        mv -i -v -n $filename $newFilename
        echo "\n"
done

echo "Done."

#EOF

Хорошо работает переименование файлов с неподдерживаемыми символами, но не ведущие и обучающие пробелы.

Вот фактический вывод, где я заменил некоторые имена в целях безопасности:

оригинал:

./ABC- Financing/2018 - ABC Capital Bl Fund 2018 (VCCI)/0 - Dataroom/8 - Vérification diligente/3. Governance/ 2017Q1/ Documents de Julie/@eaDir/ PPP@SynoResource

новый:

./ABC - Financing/2018 - ABC Capital Innovation Fund 2018 (GGGG)/0 - Dataroom/8 - Vérification diligente/3. Governance/2017Q1/Documents de Julie/@eaDir/PPP@SynoResource

./ABC - Financing/2018 - ABC Capital Innovation Fund 2018 (GGGG)/0 - Dataroom/8 - Vérification diligente/3. Governance/ 2017Q1/ Documents de Julie/@eaDir/ CDP@SynoResource./ABC - Financing/2018 - ABC Capital Innovation Fund 2018 (GGGG)/0 - Dataroom/8 - Vérification diligente/3. Governance/2017Q1/Documents de Julie/@eaDir/PPP@SynoResource

mv: cannot move "./ABC - Financing/2018 - ABC Capital Innovation Fund 2018 (GGGG)/0 - Dataroom/8 - Vérification diligente/3. Governance/ 2017Q1/ Documents de Julie/@eaDir/ PPP@SynoResource" to "./ABC - Financing/2018 - ABC Capital Innovation Fund 2018 (GGGG)/0 - Dataroom/8 - Vérification diligente/3. Governance/2017Q1/Documents de Julie/@eaDir/PPP@SynoResource": No such file or directory

Я не понимаю, почему файл не найден командой mv.

Ответы [ 2 ]

1 голос
/ 26 июня 2019

Начните с этого (использует GNU-версии find и sed):

#/bin/env bash

readarray -d '' paths < <(find . -depth -print0)
for old in "${paths[@]}"; do
     printf 'Working on path %q\n' "$old" >&2
     new=$(
         printf '%s' "$old" |
         sed -z '
             s#[\\":<>;|*?]##g
             s#[[:space:]]*/[[:space:]]*#/#g
             s#[[:space:]]*$##
         '
     )
     if [[ "$new" != "$old" ]]; then
         printf 'old: %q\n' "$old" >&2
         printf 'new: %q\n' "$new" >&2
         [[ -f "$new" ]] && printf 'Warning: %q already exists.\n' "$new" >&2
         mv -i -v -n -- "$old" "$new"
         printf '\n'
     fi
done

Вероятно, вы можете заменить printf | sed на некоторые встроенные функции bash для повышения производительности, но жизнь слишком коротка, чтобы я мог попытатьсяПоймите, что все вышеперечисленное должно быть ясным и достаточно простым для любых других изменений, которые вам нужно внести.

Вышеприведенное не проверено, поэтому убедитесь, что вы сделали резервную копию своих файлов и тщательно проверили ее на временном диске, прежде чемработает на ваших реальных файлах.

0 голосов
/ 26 июня 2019

Давайте попробуем сделать это безопасно и правильно, вместо этого:

#!/usr/bin/env bash

shopt -s extglob # setup extended globbing so it can match group multipe times

# Find all files or directories names that:
# either starts with spaces,
# or ends with spaces,
# or contains any of the \ " : < > ; | * ? prohibited characters
find . \
  -depth \
  \( -type f -or -type d \) \
  -regextype posix-extended \
  -regex '.*/([[:space:]].*|.*[[:space:]]|.*[\\":<>;|*?].*)' \
  -print0 \
  | while IFS= read -r -d '' filename; do

    # Isolates the file name from its directory path
    base="$(basename -- "${filename}")"

    # ExtGlob strips-out all instances of prohibited characters class using //
    # [\\\":<>;|*?]
    base="${base//[\\\":<>;|*?]/}"

    # ExtGlob strips-out leading spaces
    # *([[:space:]]):
    # * 0 or any times the following (group)
    # [[:space:]] any space character
    base="${base/*([[:space:]])/}"

    # ExtGlob strips-out trailing spaces using %%
    base="${base%%*([[:space:]])}"

    # Compose a new file name from the new base
    newFilename="$(dirname -- "${filename}")/${base}"

    # Prevent the new file name to collide with existing files
    # by adding a versionned suffix
    suffix=''
    count=1
    while [[ -e "${newFilename}${suffix}" ]]; do
      suffix=".$((count++))"
    done
    newFilename="${newFilename}${suffix}"

    printf \
      "original: '%s'\\nnew     : '%s'\\n\\n" \
      "${filename}" \
      "${newFilename}"
    mv -- "${filename}" "${newFilename}"

  done

echo 'Done.'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...