重定向到全域文件名失敗
我在帶有 LEMP 堆棧的 Ubuntu 16.04 (xenial) 中使用 Bash 4.3.48(1)。
我嘗試以
php.ini
與版本無關的方式使用printf
.**1)**版本不可知操作失敗:
printf "[PHP]\n post_max_size = 200M\n upload_max_filesize = 200M\n cgi.fix_pathinfo = 0" > /etc/php/*/fpm/zz_overrides.ini
給出以下錯誤:
bash: /etc/php/*/zz_overrides.ini: 沒有這樣的文件或目錄
**2)**版本諾斯替操作成功:
printf "[PHP]\n post_max_size = 200M\n upload_max_filesize = 200M\n cgi.fix_pathinfo = 0" > /etc/php/7.0/fpm/zz_overrides.ini
如您所見,除了
*
vs之外,兩者基本相同7.0
。
- 我沒有找到關於這個(正則表達式?)問題的線索
man printf
。- 我在 Google 中搜尋並沒有發現任何關於“允許 printf 中的正則表達式”的資訊。
為什麼與版本無關的操作失敗並且是否有任何繞過?
編輯:如果可能的話,對我來說最重要的是使用單行操作。
重定向中模式匹配的行為似乎在 shell 之間有所不同。在我的系統中,dash 和 ksh93 不會擴展模式,因此您會得到一個帶有文字
*
. Bash 擴展它(1),但前提是模式匹配一個文件。如果有更多匹配的文件名,它會抱怨。Zsh 就像您提供了多個重定向一樣工作,它將輸出重定向到所有匹配的文件。(1) 非互動式且處於 POSIX 模式時除外
如果您希望輸出轉到所有匹配的文件,您可以使用
tee
:echo ... | tee /path/*/file > /dev/null
如果您希望它只轉到一個文件,那麼問題是決定使用哪個文件。如果您想檢查是否只有一個文件與該模式匹配,請展開整個列表併計算它們。
在 bash/ksh 中:
names=(/path/*/file) if [ "${#names[@]}" -gt 1 ] ; then echo "there's more than one" else echo "there's only one: ${names[0]}" fi
在標準外殼中,
set
位置參數和$#
用於計數。當然,如果模式與任何文件都不匹配,它會保持原樣,並且由於 glob 位於中間,因此結果指向一個不存在的目錄。這與嘗試創建相同
/path/to/file
,在/path/to
存在之前,它只是在這裡我們有/path/*
,而不是字面意思,帶有星號。為了解決這個問題,您必須擴展沒有文件名的目錄名,然後將文件名附加到所有目錄。這個有點醜。。。
dirs=(/path/*) files=( "${dirs[@]/%/\/file}" )
然後我們可以使用該數組:
echo ... | tee "${files[@]}" > /dev/null
或者我們可以採取簡單的方法並循環文件名模式。在更一般的情況下,這有點不令人滿意,因為它需要為每個輸出文件執行一次主命令,或者使用臨時文件來保存輸出。
for dir in /path/* ; do echo ... > "$dir/file" done