Bash

重定向到全域文件名失敗

  • January 27, 2018

我在帶有 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 

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