如何搜索以下任意内容:
在 Linux 上查找以空格开头的文件夹,然后删除所有起始空格,以便该文件夹可以以字母或数字开头?
在 Linux 上查找以空格开头的文件,然后删除所有开头空格,以便文件可以以字母或数字开头?
答案1
find . -depth -name ' *' -exec sh -c '
for pathname do
newname=${pathname##*/}
newname=${newname#"${newname%%[! ]*}"}
newpathname=${pathname%/*}/$newname
if [ -z "$newname" ] || [ -e "$newpathname" ]; then
continue
fi
mv -v "$pathname" "$newpathname"
done' sh {} +
上述代码查找当前目录中或当前目录下任何名称以至少一个空格字符开头的文件或目录。它按深度优先顺序执行此操作(由于-depth
),以避免重命名尚未处理其内容的目录;否则,重命名目录会导致find
以后找不到它,因为它已被重命名。
为批量以空格开头的名称调用一个简短的内联 shell 脚本。该脚本迭代给定的路径名,并首先将当前路径名末尾的实际名称提取到变量中newname
。它使用标准参数替换 来完成此操作,删除字符串中${pathname##*/}
最后的所有内容(最长的前缀匹配),留下最终的路径名组件。这与本例基本相同。/
*/
"$(basename "$pathname")"
然后,我们需要修剪掉 中字符串开头保证存在的空格$newname
。为此,我们首先删除除空格之外的所有内容${newname%%[! ]*}
(最长的后缀匹配,即从第一个非空格字符开始),然后从字符串[! ]*
的开头删除结果。$newname
${newname#"${newname%%[! ]*}"}
命令中的目标路径由斜杠连接mv
的目录路径和新名称 ie 组成,与 本质上相同。$pathname
${pathname%/*}/$newname
"$(dirname "$pathname")/$newname"
该代码检测名称冲突并默默地跳过对可能发生冲突的名称的处理。它还会跳过折叠为空字符串的名称。这就是if
之前声明mv
的作用。如果您想让用户注意到这些名称,请在 之前这样做continue
。
测试运行在复制您的备份数据。
测试运行上面的代码:
$ tree -Q
"."
|-- " dir0"
| |-- " o dir1"
| | |-- " otherfile"
| | `-- "dir2"
| | |-- " dir3"
| | `-- " moar"
| `-- "file"
`-- "script"
4 directories, 4 files
$ sh script
./ dir0/ o dir1/dir2/ moar -> ./ dir0/ o dir1/dir2/moar
./ dir0/ o dir1/dir2/ dir3 -> ./ dir0/ o dir1/dir2/dir3
./ dir0/ o dir1/ otherfile -> ./ dir0/ o dir1/otherfile
./ dir0/ o dir1 -> ./ dir0/o dir1
./ dir0 -> ./dir0
请注意它是如何从目录层次结构的底部开始的。如果它先尝试重命名dir0
,则稍后将无法输入它来重命名其他目录和文件。
$ tree -Q
"."
|-- "dir0"
| |-- "file"
| `-- "o dir1"
| |-- "dir2"
| | |-- "dir3"
| | `-- "moar"
| `-- "otherfile"
`-- "script"
4 directories, 4 files
答案2
该脚本将查找以空格开头的文件并打印出它将运行的命令。您必须取消注释实际的 mv 命令才能使该脚本正常工作。它应该在您想要的目录中运行。它将对当前目录内的所有文件和文件夹进行此更改,但不会对当前目录中的任何子目录进行此更改。您可能有两个名为“ 123
”和“ 123
”的文件,并且您的指令会将其重命名为相同的内容。
它是不可逆的,尽管我在 mv 中添加了 -i ,所以它不会覆盖文件,除非你告诉它。在运行此脚本之前我会非常小心,包括对系统进行备份,以防系统崩溃。
#!/bin/bash
# tell read not to word split
IFS=
# find all files starting with space
find ./ -maxdepth 1 -name " *" -print0 | \
while read -d '' a
do
# new filename without leading spaces
nm=$( echo "$a" | sed 's/^.\/ */.\//')
# use -i to not overwrite files
echo mv -i \"$a\" \"$nm\"
# uncomment the next line to do the actual move
#mv -i "$a" "$nm"
done
答案3
和zsh
:
autoload -Uz zmv
zmv -n '(**/) ##(*)(#qD/)' '$1$2'
(-n
如果满意,请从试运行中删除)