ls命令,其中管道在传递到while循环中时不起作用



我试图执行这个命令:

#!/bin/sh
cmd="ls *.txt | sed s/.txt//g"
for i in `$cmd`
do
echo $i
echo "Hello world"
done 

也就是说,在当前工作目录中获取扩展名为.txt的东西,并从文件中删除.txt部分并打印出来。然而,我得到了这个错误,并且ls似乎正在解释"|"以及";sed";以及";s/.txt//g";作为文字文件名:

ls: s/.txt//g: No such file or directory
ls: sed: No such file or directory
ls: |: No such file or directory

如果我将命令传递为for i in ls *.txt | sed s/.txt//g,这不是问题。我能得到一些建议吗?

几点:

  • 如果您希望这是一个bash脚本,而不是sh脚本,则需要更改shebang以调用bash
  • BashFAQ#50中描述了评估$cmd与使用cmd内容运行命令行为不同的直接原因
  • 另请参阅BashFAQ#48,描述eval容易引发安全风险的原因
  • shell有自己内置的字符串替换行为;没有理由使用CCD_ 5。请参阅bash黑客关于参数扩展的wiki页面,描述${var%suffix}如何在删除suffix的情况下扩展到$var的内容
  • ls *.txt中,不是ls评估*.txtglob:在启动ls可执行文件之前,shell本身会执行此操作。因此,运行ls根本没有意义:它是shell的内置功能,用于生成文件名列表,所以您还可以使用该列表
#!/usr/bin/env bash
for i in *.txt; do i=${i%.txt}
echo "$i"
echo "Hello world"
done

试试这个。

#!/bin/sh
for i in $(ls *.txt | sed s/.txt//g)
do
echo $i
echo "Hello world"
done 

简单有效。

基本问题是扩展的顺序(请参阅man-bash中的EXPRANSION(:

展开的顺序是:大括号展开、波浪号展开、,参数、变量和算术展开及命令替换(以从左到右的方式完成(、分词和路径名膨胀

换句话说,命令替换已经假设原始行被拆分为各个命令,并且它将无法识别"|"、";",以及其他bash关键字。

如果命令是常量,简单的解决方案是内联它:

for i in `ls *.txt | sed s/.txt//g`

从OP来看,命令似乎必须是可变的。在这种情况下,可以使用"eval"强制将变量重新解析到管道中:

for i in `eval $cmd`

确保阅读所有关于使用";eval";,以及动态构建命令。

次要注释:在sed中,命令的/.txt//g'假定.txt是正则表达式。因此,它将把btxt.txt更改为.txt。请确保转义"。"从而将其视为文字。

cmd="ls *.txt | sed -e 's/.txt//g'

相关内容

  • 没有找到相关文章

最新更新