[英]How to Make a "for loop" Recursive
我有一個命令似乎成功地將當前目錄中的文件名的雙引號 (") 替換為單引號 (')。但是,我需要遞歸地執行此操作(即,所有子目錄中的所有文件)。這是我的代碼正在與:
for f in *; do
if [[ -f "$f" ]]; then
new_name=$(echo "$f" | sed "s/\"/'/g")
mv "$f" "$new_name"
fi
done
任何建議將不勝感激。
最佳實踐(以及當您處理大型且深層嵌套的目錄樹時更有效的解決方案)是為此使用find
,而不是 bash 中的for
循環。 使用 Find進入-print0
、 -exec
和-execdir
之間的權衡; 在這里,我使用的是最后一個:
#!/usr/bin/env bash
# define the function we're going to export for access from a subprocess
do_replace() {
local name new_name old_quotes='"' new_quotes="'"
for name do # loops by default over "$@", the argument list given to the function
new_name=${name//$old_quotes/$new_quotes}
mv -- "$name" "$new_name"
done
}
export -f do_replace # actually export that function
# tell find to start a new copy of bash that can run the function we exported
# in each directory that contains one or more file or directory names with quotes.
# Using ``-execdir ... {} ';'`` to work around a MacOS bug
# ...use ``-execdir ... {} +`` instead with GNU find for better performance.
find . -depth -name '*"*' -execdir bash -c 'do_replace "$@"' _ {} ';'
這樣每個目錄都有一個新的 bash 副本,因此您不會對其中帶有/
s 的名稱進行操作; 這避免了如果您在不同用戶可以寫入的目錄中重命名文件時可能發生的一些安全漏洞。
也就是說,最簡單的事情(在 bash 4.0 或更高版本中)是啟用globstar
,之后**
將遞歸:
#!/usr/bin/env bash
# WARNING: This calculates the whole glob before it runs any renames; this can be very
# inefficient in a large directory tree.
case $BASH_VERSION in ''|[123].*) echo "ERROR: Bash 4.0+ required" >&2; exit 1;; esac
shopt -s globstar
for f in **; do
: "put your loop's content here as usual"
done
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.