Я пытаюсь переименовать все файлы в папке, заменяя подчеркивания пробелами.
i.e. this_is_a_test --> this is a test
но почему-то я испортил цитату
> for file in * ; do echo mv -v $file $(echo $file | sed 's/_/\\ /g') ; done
mv -v this_is_a_test this\ is\ a\ test
, которая выглядит нормально, но если я уберу 'echo' mv
, то будет жаловаться, как будто удалены обратные слэши
> for file in * ; do mv -v $file $(echo $file | sed 's/_/\\ /g') ; done
mv: target ‘test’ is not a directory
Кто-то может указать на ошибку моих путей?
Есть небольшая ошибка. Используйте "$newfile"
вместо только $newfile
. Вам нужно использовать "
Вот правильный.
for file in * ; do mv -v "$file" "$(echo $file | sed 's/_/\\ /g')" ; done
Если у вас есть имя файла this_is_a_test
, оно переименует файл в this\ is\ a\ test
.
В случае, если вы хотите переименовать файл в this is a test
. Используйте приведенный ниже код,
for file in * ; do mv -v "$file" "$(echo $file | sed 's/_/ /g')" ; done
Хорошей практикой является использование переменных внутри ""
при написании хорошего сценария оболочки.
Использование rename
:
rename -n 's/_/ /g' *
Если все в порядке, удалите переключатель -n
:
rename 's/_/ /g' *
~/tmp$ tree
.
├── file
├── file_1
├── file_2
├── file_3
└── file_with_underscores
0 directories, 5 files
~/tmp$ rename 's/_/ /g' *
~/tmp$ tree
.
├── file
├── file 1
├── file 2
├── file 3
└── file with underscores
0 directories, 5 files
Вместо mv -v "$file" "$(echo $file | sed 's/_/\\ /g')"
вы можете использовать гораздо более простую команду mv "$f" "${f//_/ }"
.
Чтобы добавить его в свой скрипт:
for f in * ; do mv "$f" "${f//_/ }" ; done
И это все.
Используйте команды find
и rename
:
find <your_start_folder> -type f -regex ".*_+.*" -exec rename 's/_/ /g' {} \;
Эта команда рекурсивно переименовывает весь файл с _
в имени файла.
Объяснение
-regex ".*_+.*"
Найти все файлы с хотя бы одним _
в имени файла
_
Заменить все вхождения _
…
… пробелом ( )
Пример
% ls -Rog
.:
total 4
drwxrwxr-x 2 4096 Jun 15 17:39 foo
-rw-rw-r-- 1 0 Jun 15 17:34 foo_bar
./foo:
total 0
-rw-rw-r-- 1 0 Jun 15 17:32 foo_bar
% find . -type f -regex ".*_+.*" -exec rename 's/_/ /g' {} \;
% ls -Rog
.:
total 4
drwxrwxr-x 2 4096 Jun 15 17:40 foo
-rw-rw-r-- 1 0 Jun 15 17:34 foo bar
./foo:
total 0
-rw-rw-r-- 1 0 Jun 15 17:32 foo bar
Вот версия awk + for loop:
for filename in *; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done
И вот она в действии
$ ls
$ echo "TEST" | tee {foo,bar}_{yolo,swag}_{whatever,else}.txt
TEST
$ ls
bar_swag_else.txt bar_yolo_else.txt foo_swag_else.txt foo_yolo_else.txt
bar_swag_whatever.txt bar_yolo_whatever.txt foo_swag_whatever.txt foo_yolo_whatever.txt
$ for filename in *; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done
$ ls
bar swag else.txt bar yolo else.txt foo swag else.txt foo yolo else.txt
bar swag whatever.txt bar yolo whatever.txt foo swag whatever.txt foo yolo whatever.txt
Для учета перевода строки и возможного переименования каталогов Вот типичная конструкция цикла IFS + find + read + while. После выполнения предложения сначала запустите версию с find . -type d -print0
, потому что если вы начнете сначала переименовывать файлы, а подкаталог содержит подчеркивание, имя файла не изменится. Короче говоря, сначала позаботьтесь о каталогах и подкаталогах, а затем позаботьтесь о файлах
$ ls
file_bar_swag.txt file_bar_yolo.txt file_test_swag.txt file_test_yolo.txt foo_bar_swag.txt foo_bar_yolo.txt foo_test_swag.txt foo_test_yolo.txt tester_dir
$ ls tester_dir/
ber_sweg_elze.txt ber_sweg_whut.txt ber_yelo_elze.txt ber_yelo_whut.txt fee_sweg_elze.txt fee_sweg_whut.txt fee_yelo_elze.txt fee_yelo_whut.txt
$ find . -type d -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done
mv: ‘.’ and ‘./.’ are the same file
$ ls
file_bar_swag.txt file_bar_yolo.txt file_test_swag.txt file_test_yolo.txt foo_bar_swag.txt foo_bar_yolo.txt foo_test_swag.txt foo_test_yolo.txt tester dir
$ find . -type f -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done
mv: ‘./.yolo’ and ‘./.yolo’ are the same file
$ ls
file bar swag.txt file bar yolo.txt file test swag.txt file test yolo.txt foo bar swag.txt foo bar yolo.txt foo test swag.txt foo test yolo.txt tester dir
Как видите, есть небольшая проблема - потому что команда find также перечисляет текущий каталог (обозначается символом a. ) команда создаст побочный продукт - файл с начальной точкой.
Добавление ! -path .
при работе с каталогами решает проблему
$ find . ! -path . -type d -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done
$ find . -type f -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done
$ ls
file bar swag.txt file bar yolo.txt file baz swag.txt file baz yolo.txt foo bar swag.txt foo bar yolo.txt foo baz swag.txt foo baz yolo.txt tester dir
$ ls "tester dir"
file bar.txt file baz.txt foo bar.txt foo baz.txt
$ ls -a
. .. file bar swag.txt file bar yolo.txt file baz swag.txt file baz yolo.txt foo bar swag.txt foo bar yolo.txt foo baz swag.txt foo baz yolo.txt tester dir