Shell-Script

根據副檔名將文件移動到目錄(zsh,macOS)

  • March 22, 2022

我想要一個腳本來自動將所有文件移動到我已經到位的目錄結構中(它看起來像~/jpg, ~/png, ~/mp3,~/zip等等)。到目前為止,這幾乎完全符合我的要求:

#!/bin/zsh
echo "Executing Script"
find . -iname '*.jpg' -exec gmv -i --target-directory=$HOME/jpg '{}' +
find . -iname '*.png' -exec gmv -i --target-directory=$HOME/png '{}' +

我沒有使用 shell 腳本的經驗,所以這只是我設法拼湊起來的東西。

簡單地在連續的行上發出連續的命令是為 shell 編寫腳本的正確方法嗎?我最初嘗試過這個,mv並且涉及到錯誤處理,而且它並不優雅。我正在嘗試在這裡擴展使用者 EvilSoup 的答案。

除了我已經提到的之外,我還包括了mv -i標誌**,這樣我就不會覆蓋任何已經存在**的東西(這部分非常重要),但也許這-n更好,我不確定。

關於find我希望這些mv操作只發生在目前目錄中,並且由於某種原因,find似乎有點遞歸,儘管我不完全了解如何限制它。我想在每個目錄中執行我的腳本,並且mv 只有find在目前工作目錄中找到的文件。

+1 用於任何 zsh-on-macOS特定的介紹性材料:shell 腳本。

你沒有做錯什麼。當您開始編寫腳本以使您的第一個腳本只是一個接一個的命令列表時,這是完全正常的。

但希望你能學會超越這一點。我並不是說你的劇本不好,但相比之下,我想向你展示我會寫什麼而不是你的劇本。我正在使用條件、循環和安全檢查,並且我添加了一堆註釋,以便您可以看到腳本在做什麼。

#!/usr/bin/env zsh

# announce that the script has started
echo "Running sorting script."

# the variable "$1" means the first argument to the script, i.e., if
# the script is named "mysorter.zsh" if you ran mysorter.zsh ~/tmp
# then $1 would be "~/tmp"
# I'm assigning that to the variable "argument"
argument="$1"

# if $argument is blank, I want the script to run in the present 
# directory; if not, I want to move to that directory first
# [[ -n "$argument" ]] means "$argument is not blank" (not length 0)
# for other conditions like -n, see 
# https://zsh.sourceforge.io/Doc/Release/Conditional-Expressions.html
if [[ -n "$argument" ]] ; then
   # [[ -d "$argument" ]] checks if "$argument" is a directory; if it's
   # not, the command is a mistake and the script should quit
   # the "!" means "not"
   if [[ ! -d "$argument" ]] ; then
       # echo prints text; the ">&2" means print to the standard error
       # stream, rather than regular output stream, because this is an
       # error message
       echo "$argument either does not exist or is not a directory" >&2
       # exit quits the script; the number indicates the error code; if
       # you write "exit 0" that means no error; but this is an error
       # so I give it a non-zero code
       exit 1
   fi
   # if we made it here, then "$argument" is indeed a folder, so I
   # move into it
   cd "$argument"
fi

# this is a loop that will be separately processed for all files in
# the active directory
for file in * ; do
   # I indent inside the loop to indicate better where the loop starts
   # and stops

   # first I check if "$file" is a folder/directory; if it is, 
   # I don't want to do anything; "continue" means cease this cycle
   # through the loop and move on to the next one
   if [[ -d "$file" ]] ; then
       continue
   fi

   # what I want to do next depends on the extension of "$file";
   # first I will determine what that is
   # the notatation "${file##*.}" means cut off everything prior to
   # the final . ; 
   # see https://zsh.sourceforge.io/Doc/Release/Expansion.html#Parameter-Expansion
   extension="${file##*.}"

   # i want to treat extensions like JPG and jpg alike, so I will make
   # the extension lowercase; see the same page above
   extension="${(L)extension}"

   # I want to move the file to a folder in $HOME named after the 
   # extension, i.e., $HOME/$extension; first I check if it doesn't
   # exist yet
   if [[ ! -d "$HOME/$extension" ]] ; then
       # since it doesn't exist, I will create it
       mkdir "$HOME/$extension"
   fi

   # by default we want the move target to have the same name
   # as the original file
   targetname="$file"
   # but I may need to add a number to it; see below
   num=0
   # now I want to check if there is already a file in there with
   # that name already, and keep changing the target filename
   # while there is
   while [[ -e "$HOME/$extension/$targetname" ]] ; do
       # a file with that name already exists; but I still want
       # to put the file there without overwriting the other one;
       # I will keep checking numbers to add to the name until I
       # find one for a file that doesn't exist yet
       
       # increase by one
       let num++
       
       # the new targetname is filename with the extension cut off, 
       # plus "-$num" plus the extension
       # e.g. "originalfilename-1.zip"
       targetname="${file%.*}-${num}.${extension}"
   done

   # we have now found a safe file name to use for the target, 
   # so we can move the file
   echo "Moving file $file to $HOME/$extension/$targetname"
   # here we try to move the file, but if it fails, we 
   # print an error and quit the script with an error
   if ! mv "$file" "$HOME/$extension/$targetname" ; then
       echo "Move command failed!" >&2
       exit 1
   fi
   
   # we're now done with this file and can move on to the next one
done
# done indicates the end of the loop
#
# if we got here everything was successful and quit with exit code 0
echo "All files successfully sorted."
exit 0

這只是為了讓您了解什麼是可能的。

不要擔心你的腳本馬上就完美了。當你得到更多的練習時,你會變得更好。如果腳本適合您,它們也適合您。

顯然,我添加了一些指向https://zsh.sourceforge.io的連結,這是了解有關 zsh 的更多資訊的好資源。

我不會添加任何特定於 mac 的內容,因為您應該嘗試學習不要被任何一個平台束縛,特別是如果您可能預見自己會從專有平台轉向那些開源並真正接受UNIX 哲學的平台。(我正在盡我所能不說教。它有效嗎?)

引用自:https://unix.stackexchange.com/questions/696200