我正在尝试重命名文件夹中的所有文件,并用空格替换下划线。
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
有人能指出我的错误吗?
答案1
使用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
答案2
有一个小错误。使用"$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
""
在编写好的 shell 脚本时,使用内部变量是一种很好的做法。
答案3
您可以mv -v "$file" "$(echo $file | sed 's/_/\\ /g')"
使用更简单的命令mv "$f" "${f//_/ }"
。
要将其添加到您的脚本中:
for f in * ; do mv "$f" "${f//_/ }" ; done
就是这样。
答案4
以下是 awk + for 循环版本:
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 命令也列出了当前目录(用 . 表示),所以该命令将创建一个副产品 - 一个以点为前导的文件。
! -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