2014-01-21 7 views
0

Я пытался написать сценарий для переименования всех файлов, содержащих пробел, и замены пространства тире.Bash - поиск файлов с пробелами и переименование с помощью sed

Пример: «Эй Bob.txt» на «Эй-Bob.txt»

Когда я использовал для цикла, он просто разделить имя файла в пространстве, так «Эй Bob.txt» дал отдельный аргумент, как «Эй» и «Боб.txt».

Я попробовал следующий скрипт, но он держится на мне.

#!/bin/bash
find/-name '* *' -exec mv {} $(echo {} | sed 's/ /-g')\;

+0

почти наверняка процитировать проблема, но я не уверен, если процитировать '{}' необходимо или поможет. Стоит попробовать, верно? Еще, вернитесь к вашему решению цикла и dbl-quote все ссылки на переменные. Удачи. – shellter

ответ

1

Строительство от идеи OP еще:

find ${PATH_TO_FILES} -name '* *' -exec bash -c 'eval $(echo mv -v \"{}\" $(echo {} | sed "s/ /-/g"))' \; 
  • ПРИМЕЧАНИЕ: необходимо указать PATH_TO_FILES переменную

EDIT: BroSlow отметил необходимость учитывать структуру каталогов:

find ${PATH_TO_FILES} -name '* *' -exec bash -c 'DIR=$(dirname "{}" | sed "s/ /-/g"); BASE=$(basename "{}"); echo mv -v \"$DIR/$BASE\" \"$DIR/$(echo $BASE | sed "s/ /-/g")\"' \; > rename-script.sh ; sh rename-script.sh 
+0

Добавил бы '-type f', чтобы избежать ошибок, но +1 для фантазии одного лайнера. – BroSlow

+0

Я подумал об этом, но потом подумал: «Что, если OP хочет переименовать каталоги Hey Bob?» или даже символические ссылки «Hey Bob» :) – csiu

+1

Возможно, он хотел, но он полностью изменит деревья каталогов, и вам все равно придется создавать несуществующие каталоги до того, как вы каким-либо образом разместите файлы mv в одном лайнере. Так, например, «/ home/foo/some space dir/some file» не удастся, даже если 'mv' get обработан правильно в вашем примере выше, потому что он попытается« mv' его в »/ home/foo/some-space-sir/some-file " – BroSlow

0

Не одна линия, но избегает sed и должен работать так же хорошо, если вы собираетесь использовать его для сценария в любом случае. (Заменить mv с echo, если вы хотите проверить)

В Баш 4+

#!/bin/bash 
shopt -s globstar 
for file in **/*; do 
    filename="${file##*/}" 
    if [[ -f $file && $filename == *" "* ]]; then 
    onespace=$(echo $filename) 
    dir="${file%/*}" 
    [[ ! -f "$dir/${onespace// /-}" ]] && mv "$file" "$dir/${onespace// /-}" || echo "$dir/${onespace// /-} already exists, so not moving $file" 1>&2 
    fi 
done 

Старые Баш

#!/bin/bash 
find . -type f -print0 | while read -r -d '' file; do 
    filename="${file##*/}" 
    if [[ -f $file && $filename == *" "* ]]; then 
    onespace=$(echo $filename) 
    dir="${file%/*}" 
    [[ ! -f "$dir/${onespace// /-}" ]] && mv "$file" "$dir/${onespace// /-}" || echo "$dir/${onespace// /-} already exists, so not moving $file" 1>&2 
    fi 
done 

Объяснение алгоритма

  • **/* Это рекурсивен список всех файлов в текущем каталоге (** технически это делает, но /* добавляется в конце, так что не отображает сам каталог)
  • ${file##*/} будет искать самые длинные картины */ в файле и удалите его из строки. например /foo/bar/test.txt печатаются в test.txt
  • $(echo $filename) Без процитировать эхо будет усечение пространства к одному, что делает их легче заменить одним - для любого количества пробелов
  • ${file%/*} Удалить все после того, как и в том числе последнего /, например,/foo/bar/test.txt печатает /foo/bar
  • mv "$file" ${onespace// /-} заменить каждый пробел в нашем имени файла с - (мы проверяем, если hyphened версия существует, прежде чем руки, и если он делает эхо, что он не в стандартный вывод, отметить && обрабатывается до || в Баш)
  • find . -type f -print0 | while read -r -d '' file Этом используется, чтобы избежать разбивать строки с пробелами в них, установив ограничитель и не обрабатывает \

Пример вывода

$ tree 
. 
├── bar 
│   ├── some dir 
│   │   ├── some-name-without-space1.pdf 
│   │   ├── some name with space1.pdf 
│   ├── some-name-without-space1.pdf 
│   ├── some name with space1.pdf 
│   └── some-name-with-space1.pdf 
└── space.sh 
$ ./space.sh 
bar/some-name-with-space1.pdf already exists, so not moving bar/some name with space1.pdf 
$ tree 
. 
├── bar 
│   ├── some dir 
│   │   ├── some-name-without-space1.pdf 
│   │   ├── some-name-with-space1.pdf 
│   ├── some-name-without-space1.pdf 
│   ├── some name with space1.pdf 
│   └── some-name-with-space1.pdf 
└── space.sh 
0

Другой способ:

find . -name "* *" -type f |while read file 
do 
    new=${file// /} 
    mv "${file}" $new 
done 
+0

Это не очень надежный, если в имени файла есть другие специальные символы и, очевидно, не будет работать вообще, если есть имена с символами новой строки. – tripleee

Смежные вопросы