我有一个目录,其中填充了由用户上传的PDFS,并且没有意识到需要遵循某些命名约定才能再次下载这些文件。为了解决问题,我需要运行一个bash脚本或命令,它将递归地遍历子目录并删除坏字符并重命名文件。
我以为我已经弄明白了,但是唉,我被困在一个方面。一旦我运行我的命令(见下文),我会收到大量错误,显示其找到文件,但移动的参数列表(目标)未正确设置。如何将文件名传递给子命令?
find . -name '*.pdf' -or -name '*.PDF' -execdir mv -v '{}' `echo {} | tr ' ' '_' | tr -d '[{}(),\!]' | tr -d "\'" | tr '[A-Z]' '[a-z]' | sed 's/_-_/_/g'`\;
我知道我的问题是echo {},但我不知道如何在那里找到find找到的文件名。第一个替换是有效的,回声不是。
提前致谢!
答案 0 :(得分:2)
ShellCheck帮助您指出三个问题:
-execdir
-or
ignores everything 您的\;
必须是a separate argument
`..`
将expand once,而不是找到找到的文件。此外,
tr
中的{}由find tr
参数不应该围绕[]
考虑所有这些:
find . \( -name '*.pdf' -or -name '*.PDF' \) \
-execdir sh -c 'mv -v "$1" "$(echo "$1" | tr " " "_" | tr -d "{()},\!'\''" | tr "A-Z" "a-z" | sed "s/_-_/_/g")"' _ {} \;
答案 1 :(得分:0)
这不起作用,因为您的命令替换(由反引号分隔)是在find
命令执行之前完成的,因此{}
尚不可用。我建议通过将替换拉出到循环遍历find
的结果来重构命令:
find . -print0 -name '*.pdf' -or -name '*.PDF' |
while read -d $'\0' -r name ; do
pushd $( dirname "$name" ) &>/dev/null
newname=$( tr ' ' '_' <<<"$name" |
tr -d '[{}(),\!]' |
tr -d "\'" |
tr '[A-Z]' '[a-z]' |
sed 's/_-_/_/g' )
mv "$name" "$newname"
popd &>/dev/null
done
此示例中的find
命令使用print0
选项将其结果与\0
个字符分开。指示循环头部中的read
忽略转义序列(-r
)并使用\0
个字符作为分隔符(-d
)。 pushd
和popd
用于模拟您在原始命令中的find
-execdir
行为。
答案 2 :(得分:-2)
将一个命令输入另一个命令:
command1 | command2