
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png
它只會移動.png
找到的第一個文件,而不是所有文件。
如何使該命令應用於與通配符匹配的所有檔案?
答案1
mv1 *.png
首先將通配符模式擴展*.png
為匹配檔案名稱列表,然後將該檔案名稱列表傳遞給函數。
然後,在函數內部$1
意味著:將第一個參數傳遞給函數,在包含空格的地方將其拆分,並替換任何包含通配符的空格分隔部分,並透過匹配檔案名稱清單來匹配至少一個檔案名稱。聽起來很複雜?確實如此,而且這種行為只是偶爾有用,而且經常會出現問題。這種拆分和匹配行為僅發生$1
在雙引號之外,因此修復很簡單:使用雙引號。始終在變數替換兩邊加上雙引號除非你有充分的理由不這麼做。
例如,如果目前目錄包含兩個檔案A* algorithm.png
和graph1.png
,則作為第一個參數mv1 *.png
傳遞A* algorithm.png
給函數,並graph1.png
作為第二個參數傳遞。然後$1
分為A*
和algorithm.png
。此模式A*
符合A* algorithm.png
, 且不algorithm.png
包含通配符。因此函數最終mv
以參數-n
、A* algorithm.png
、algorithm.png
和運行targetdir
。-v
如果您將函數更正為
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
那麼它將正確移動第一個檔案。
處理全部參數,告訴 shell 處理所有參數而不僅僅是第一個參數。您可以使用"$@"
來表示傳遞給函數的參數的完整清單。
function mv1 { mv -n "$@" "targetdir" -v |wc -l ;}
這幾乎是正確的,但如果檔案名稱恰好以字元 開頭-
,它仍然會失敗,因為mv
會將該參數視為選項。傳遞--
tomv
告訴它“此後沒有更多選項”。這是大多數命令都支援的非常常見的約定。
function mv1 { mv -n -v -- "$@" "targetdir" |wc -l ;}
剩下的問題是,如果mv
失敗,函數將返回成功狀態,因為管道左側命令的退出狀態被忽略。在 bash(或 ksh)中,您可以使用set -o pipefail
使管道失敗。請注意,設定此選項可能會導致同一 shell 中運行的其他程式碼失敗,因此您應該在函數中本地設定它,這從 bash 4.4 開始是可能的。
function mv1 {
local -
set -o pipefail
mv -n -v -- "$@" "targetdir" | wc -l
}
在早期版本中,設定pipefail
會很脆弱,因此最好PIPESTATUS
明確檢查。
function mv1 {
mv -n -v -- "$@" "targetdir" | wc -l
((!${PIPESTATUS[0] && !${PIPESTATUS[1]}}))
}
答案2
$1
是函數的第一個參數,這裡是第一個符合的檔案*.png
。我想這"$@"
就是您想要使用的而不是$1
.
答案3
你必須使用mv1 \*.png
.
與函數互動時,Linux 終端不會直接將星號傳遞給命令,而是選擇第一個符合的參數並將其傳遞給命令。
為了讓星號直接通過,需要使用反斜線轉義星號。