简体   繁体   中英

BASH Linux - How to pass the result of find into a mv destination via echo

I have a directory which is filled with PDFS that were uploaded by a user and that didnt realize that certain naming conventions needed to be followed to have the files be downloadable again. To fix the issue en mass, I need to run a bash script or command that will recursively spider through the subdirectories and strip out the bad characters and rename the files.

I thought I had it all figured out, but alas, I am stuck on one part. Once I run my command (see below) I get a host of errors showing its finding the files, but the argument list for move (the destination) isnt being set properly. How do I pass the filename into the sub-command?

find . -name '*.pdf' -or -name '*.PDF' -execdir mv -v '{}' `echo {} | tr ' ' '_' | tr -d '[{}(),\!]' | tr -d "\'" | tr '[A-Z]' '[a-z]' | sed 's/_-_/_/g'`\;

I know my issue is the echo {} thing, but I have no idea how to get the filename found by find in there. The first substitution works, the echo one doesnt.

Thanks in advance!

ShellCheck helpfully points out three issues with your command:

  1. Your -execdir ignores everything before the -or

  2. Your \\; has to be a separate argument

  3. Your `..` will expand once before find runs, not per file found.

Additionally,

  • The {} in the tr is interpretted by find
  • tr arguments should not have [] around them

Accounting for all this:

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")"' _ {} \;

This does not work because your command substitution (delimited by the backticks) is done before the find command is executed, so {} is not yet available. I'd suggest restructuring your command by pulling out the substitutions to a loop that iterates over find 's results:

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

The find command in this example used the print0 option to separate its results with \\0 characters. read in the loop's head is instructed to ignore escape sequences ( -r ) and use the \\0 characters as delimiters ( -d ). pushd and popd are used to emulate find 's -execdir behavior that you had in your original command.

像这样将一个命令传递给另一个命令:

command1 | command2  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM