简化bash脚本?

时间:2012-11-15 19:26:03

标签: bash

必须有一种方法可以在下面粗略构建的脚本中对这3条查找行进行流式处理...

#!/usr/bin/bash
#
#
if [ "find /data -type f -perm 400 -print" ] ; then
    find /data -type f -perm 400 -exec echo Modifying {} \;
    find /data -type f -perm 400 -print | xargs chmod 755
else
    echo 'No files to modify'
fi

2 个答案:

答案 0 :(得分:4)

您可以将其更改为以下内容:

found=$(find /data -type f -perm 400 -print -quit)

if [ "$found" ]; then
    find /data -type f -perm 400 -exec echo Modifying {} \; -exec chmod 755 {} \; 
else
    echo 'No files to modify`
fi

<强>解释

  • find /data -type f -perm 400 -print -quit:一旦在400中找到具有权限/data第一个文件,它就会打印文件名并立即终止查找。打印件保存到变量found(因此我们知道是否输出“无需修改的文件”或不在以后输出。)
  • -exec echo Modifying {} \; -exec chmod 755 {} \;:您可以通过此链接语法
  • 对find返回的每个结果执行多个命令
  • 注意:显然find会在找不到任何内容时返回0,因此使用$?无效。

答案 1 :(得分:4)

while read -d $'\0' file; do
    found=yes
    echo "Modifying $file"
    chmod 755 "$file"
done < <(find /data -type f -perm 400 -print0)
if [ "x$found" != "xyes" ]; then
    echo "No files found to modify"
fi

这使用process substitution feature in Bash。它相当于

find ... | while read ...

除了那种情况,while read在子shell中执行,因此我们无法设置将在外壳中看到的变量。相反,我们可以使用流程替换。 <(cmd)在子shell中运行cmd,其标准输出重定向到命名管道。该管道的名称将替换为外部命令。

然后我们使用<从此管道重定向到while read命令的标准输入,该命令依次读取每个分隔的记录,并将值存储在指定的名称中(file在这种情况下)。默认情况下,read会在换行符上中断。对于大多数文件,这没关系;你可以这样做:

while read file; do
    ...
done < <(find /data -type f -perm 400)

它会正常工作。但是技术上可以在文件名中添加换行符,在这种情况下会破坏。要查找的-print0参数和-d $'\0'的{​​{1}}参数会导致它们各自使用空字符作为分隔符,这在文件名中无效。