BASH Linux - 如何通过echo将find的结果传递给mv目的地

时间:2015-04-03 19:18:50

标签: linux bash

我有一个目录,其中填充了由用户上传的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找到的文件名。第一个替换是有效的,回声不是。

提前致谢!

3 个答案:

答案 0 :(得分:2)

ShellCheck帮助您指出三个问题:

  1. -execdir

    之前的-or ignores everything
  2. 您的\;必须是a separate argument

  3. 在查找运行之前,`..`expand once,而不是找到找到的文件。
  4. 此外,

    • 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)。 pushdpopd用于模拟您在原始命令中的find -execdir行为。

答案 2 :(得分:-2)

将一个命令输入另一个命令:

command1 | command2