循环时避免扩展:for x in $foo
Avoiding expansion when looping: for x in $foo
我必须计算目录中可执行文件的数量。
我已经找到了一种不同的方法(通过写入文件然后搜索文件,但这有点难看)。
首先想到的解决方案是这样的(第一个参数是目录路径):
#!/bin/bash
noe=0
files=`ls -F ` # because the -F option appends an indicator
# to the file, for an executable it's an '*'
# so if there is an executable 'script.sh' in the dir
# the output will be like this: 'script.sh*'
for i in $files
do
if [ `echo "$i" | grep '*$'` ] #should search for an '*' at the end...
then
let noe += 1
fi
done
echo $noe
这不起作用,因为在 for 循环中省略了“*”。
(for 循环中的 echo 命令输出一个文件名,但最后没有 '*',但当参数在 "" 中时,在 for 循环外正常工作")
关于这个 here 有一个类似的问题,我已经设法根据我的情况调整答案,但没有解释为什么不能用 for 完成。 + 我不太明白为什么while循环
里多了一个<
...
done < <(ls -F )
^
|_ I know that this means redirect to file to loop
Does the second < mean that we are redirecting the
standard input file? (this might be a stupid question)
另一个问题:
有没有办法用 for 循环解决这个问题?为什么?
这个问题的解决方案在任何情况下都不应该involve ls
。
您可以使用 for 循环迭代文件并使用 -x
测试来确定文件是否可执行。但是,目录通常也是可执行的(如果不是,则您无法输入它们,例如使用 cd
),因此根据您是否要在结果中包含目录,您可能需要一个 -d
测试也。示例:
for file in ./*; do
if [[ -x $file && ! -d $file ]]; then
printf '<%s> is an executable file that is not a directory\n' "$file"
(( count++ ))
fi
done
printf '%d executable files found\n' "$count"
关于第二个问题:
...
done < <(ls -F )
^
|_ I know that this means redirect to file to loop
Does the second < mean that we are redirecting the
standard input file? (this might be a stupid question)
<(...)
是进程替换,并被文件名替换为 fd 或命名管道(取决于操作系统支持的内容)。从这个 fd 或命名管道读取的任何进程都将在 <(...)
内获得命令的输出(stdout)
你可以通过将它与 echo 一起使用来查看:
$ echo <(true) # turns into echo /dev/fd/63
/dev/fd/63
所以在你的情况下,done < <(ls...)
变成类似 done < /dev/fd/63
的东西,这是你已经熟悉的标准文件重定向。
使用 find 查找文件:
#!/bin/bash
find "" -type f -executable -maxdepth 1 | wc -l
for x in $foo; do ...
...不是在数组上循环;它在 字符串 上循环。因此,要使循环执行多次,您 必须 对字符串进行某种扩展,即使扩展只是字符串拆分。
如果您关闭所有扩展,您会看到:
for x in "$foo"; do ...
...它将只执行一次,使循环无用。
现在,这里有一个中间位置:您可以暂时关闭 glob 扩展,但保留字符串拆分:
set -f # disable all globbing
for x in $foo; do # expand without globbing
...
done
set +f # turn globbing back on
请注意,此行为不一定是可预测的,除非您控制变量 IFS
的值,该变量控制字符串拆分发生在哪些字符上。
如果你想建立一个数组,你可以这样做:
array=( "first element" "second element" "third element" )
for x in "${array[@]}"; do ...
...在 的情况下,您可以安全地使用 for
。
我必须计算目录中可执行文件的数量。
我已经找到了一种不同的方法(通过写入文件然后搜索文件,但这有点难看)。
首先想到的解决方案是这样的(第一个参数是目录路径):
#!/bin/bash
noe=0
files=`ls -F ` # because the -F option appends an indicator
# to the file, for an executable it's an '*'
# so if there is an executable 'script.sh' in the dir
# the output will be like this: 'script.sh*'
for i in $files
do
if [ `echo "$i" | grep '*$'` ] #should search for an '*' at the end...
then
let noe += 1
fi
done
echo $noe
这不起作用,因为在 for 循环中省略了“*”。
(for 循环中的 echo 命令输出一个文件名,但最后没有 '*',但当参数在 "" 中时,在 for 循环外正常工作")
关于这个 here 有一个类似的问题,我已经设法根据我的情况调整答案,但没有解释为什么不能用 for 完成。 + 我不太明白为什么while循环
里多了一个<
...
done < <(ls -F )
^
|_ I know that this means redirect to file to loop
Does the second < mean that we are redirecting the
standard input file? (this might be a stupid question)
另一个问题: 有没有办法用 for 循环解决这个问题?为什么?
这个问题的解决方案在任何情况下都不应该involve ls
。
您可以使用 for 循环迭代文件并使用 -x
测试来确定文件是否可执行。但是,目录通常也是可执行的(如果不是,则您无法输入它们,例如使用 cd
),因此根据您是否要在结果中包含目录,您可能需要一个 -d
测试也。示例:
for file in ./*; do
if [[ -x $file && ! -d $file ]]; then
printf '<%s> is an executable file that is not a directory\n' "$file"
(( count++ ))
fi
done
printf '%d executable files found\n' "$count"
关于第二个问题:
... done < <(ls -F ) ^ |_ I know that this means redirect to file to loop Does the second < mean that we are redirecting the standard input file? (this might be a stupid question)
<(...)
是进程替换,并被文件名替换为 fd 或命名管道(取决于操作系统支持的内容)。从这个 fd 或命名管道读取的任何进程都将在 <(...)
你可以通过将它与 echo 一起使用来查看:
$ echo <(true) # turns into echo /dev/fd/63
/dev/fd/63
所以在你的情况下,done < <(ls...)
变成类似 done < /dev/fd/63
的东西,这是你已经熟悉的标准文件重定向。
使用 find 查找文件:
#!/bin/bash
find "" -type f -executable -maxdepth 1 | wc -l
for x in $foo; do ...
...不是在数组上循环;它在 字符串 上循环。因此,要使循环执行多次,您 必须 对字符串进行某种扩展,即使扩展只是字符串拆分。
如果您关闭所有扩展,您会看到:
for x in "$foo"; do ...
...它将只执行一次,使循环无用。
现在,这里有一个中间位置:您可以暂时关闭 glob 扩展,但保留字符串拆分:
set -f # disable all globbing
for x in $foo; do # expand without globbing
...
done
set +f # turn globbing back on
请注意,此行为不一定是可预测的,除非您控制变量 IFS
的值,该变量控制字符串拆分发生在哪些字符上。
如果你想建立一个数组,你可以这样做:
array=( "first element" "second element" "third element" )
for x in "${array[@]}"; do ...
...在 的情况下,您可以安全地使用 for
。