mik*_*ike 4 ls grep bash cygwin for
我想保留所有文件不以.bat
我试过
for f in $(ls | egrep -v .bat); do echo $f; done
Run Code Online (Sandbox Code Playgroud)
和
for f in $(eval ls | egrep -v .bat); do echo $f; done
Run Code Online (Sandbox Code Playgroud)
但是这两种方法产生相同的结果,因为它们打印所有内容。而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*
Run Code Online (Sandbox Code Playgroud)
命令正在工作,但不在 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
Run Code Online (Sandbox Code Playgroud)
调试 $ 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
Run Code Online (Sandbox Code Playgroud)
Sté*_*las 10
您的代码中有一些错误:
$(...)
不带引号的命令替换 ( ) 而不设置$IFS
不加引号的扩展是 split+glob 运算符。默认是在空格、制表符和换行符上拆分。在这里,您只想在换行符上拆分,因此您需要将 IFS 设置为该值,否则这意味着如果文件名包含空格或制表符将无法正常工作
set -f
。不加引号的扩展是 split+glob 运算符。在这里,您不需要通配符,即将通配符扩展scala*
到匹配文件列表中。当您不希望 shell 进行通配时,您必须使用以下命令禁用它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
Run Code Online (Sandbox Code Playgroud)
虽然如果当前目录中没有非隐藏文件,仍然会输出*
. 您可以解决在zsh
通过更改*
到*(N)
或者bash
通过运行shopt -s nullglob
。
您不应该使用ls
这种方式解析文件。
通过第一组extglob globstarshopt -s extglob globstar
然后
for f in !(*.bat)
do
printf '%s\n' "$f"
done
Run Code Online (Sandbox Code Playgroud)
使用 find
find . -type f ! -name '*.bat'
Run Code Online (Sandbox Code Playgroud)
使用否定运算符可以更安全地处理文件。