for循環中的命令替換不起作用
我想保留所有文件不以
.bat
我試過
for f in $(ls | egrep -v .bat); do echo $f; done
和
for f in $(eval ls | egrep -v .bat); do echo $f; done
但是這兩種方法都會產生相同的結果,因為它們會列印所有內容。而如果
ls | egrep -v .bat
與循環eval ls | egrep -v .bat
分開使用,則本身就可以工作。for
編輯
有趣的是,如果我省略了
-v
標誌,循環會做它應該做的事情並列出所有以.bat
.隨意編輯問題標題,因為我不確定問題是什麼。
我正在使用
GNU bash, version 4.1.10(4)-release (i686-pc-cygwin).
例子
$ ls -l | egrep -v ".bat" total 60K -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 fsc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scala* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalac* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scaladoc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalap*
命令正在工作,但不在 for 循環中。
$ for f in $(ls | egrep -v .bat); do echo $f; done fsc fsc.bat scala scala.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat
調試
$ set -x
mike@pc /cygdrive/c/Program Files (x86)/scala/bin $ for f in $(ls | egrep -v .bat); do echo $f; done ++ ls -hF --color=tty ++ egrep --color=auto -v .bat + for f in '$(ls | egrep -v .bat)' + echo fsc fsc + for f in '$(ls | egrep -v .bat)' + echo fsc.bat fsc.bat // and so on
您的程式碼中有一些錯誤:
使用不帶引號的命令替換 (
$(...)
) 而不設置$IFS
不加引號的擴展是 split+glob 運算符。預設是按空格、製表符和換行符分割。在這裡,您只想在換行符處拆分,因此您需要將 IFS 設置為否則這意味著如果文件名包含空格或製表符,則將無法正常工作
使用不帶引號的命令替換
set -f
.不加引號的擴展是 split+glob 運算符。在這裡您不想要萬用字元,即將萬用字元擴展為
scala*
匹配文件列表。當您不希望 shell 進行 globbing 時,您必須使用以下命令禁用它set -f
ls
別名為ls -F
上述問題因您
ls
別名為ls -F
. 它添加/
到目錄和*
執行檔中。因此,通常,因為scala
它是可執行的、ls -F
輸出scala*
的,並且作為一個通配模式,它被擴展為所有以它開頭的文件名,scala
這解釋了為什麼它似乎egrep -v
沒有過濾掉文件。假設文件名不包含換行符
換行符與文件名中的任何字元一樣有效。所以解析的輸出
ls
通常是行不通的。例如,ls
在包含a
和b
文件的目錄中的輸出與在包含一個名為a\nb
.上面
egrep
將過濾文件名的行,而不是文件名使用
egrep
代替grep -E
egrep
已棄用。grep -E
是標準等價物。不轉義
.
正則表達式運算符。上面,您曾經
egrep
啟用擴展正則表達式,但沒有使用任何擴展的 RE 特定運算符。您使用的唯一 RE 運算符是.
匹配任何字元,但看起來這不是您想要的。所以你不妨在grep -F
這裡使用。或使用grep -v '\.bat'
.不在行尾錨定正則表達式
egrep .bat
將匹配任何包含任何後跟字元的行bat
,因此這就是正則表達式,表示任何不包含bat
在第一個位置的內容。它應該是grep -v '\.bat$'
。不加
$f
引號不加引號的擴展是 split+glob 運算符。在那裡,你都不想要,所以
$f
應該引用 ("$f"
)。採用
echo
echo
在其參數中擴展 ANSI C 轉義序列和/或根據實現(和/或環境)像-n
或特別對待字元串。-e``echo
所以一個更好的解決方案:
for f in *; do case $f in (*.bat);; (*) printf '%s\n' "$f" esac done
雖然如果目前目錄中沒有非隱藏文件,那仍然會輸出
*
. 您可以zsh
通過更改*
為*(N)
或bash
執行來解決此問題shopt -s nullglob
。