【问题标题】:How to capture chown output in a ksh script如何在 ksh 脚本中捕获 chown 输出
【发布时间】:2016-02-03 18:49:49
【问题描述】:

我编写了一个脚本来根据读入的输入列表更改文件所有权。我的脚本在名称中没有空格的目录上运行良好。但是,它无法更改名称中带有空格的目录上的文件。我还想将 chown 命令的输出捕获到文件中。有人可以帮忙吗?

这是我在 ksh 中的脚本:

#!/usr/bin/ksh

newowner=eg27395

dirname=/home/sas/sastest/
logfile=chowner.log
date > $dir$logfile
command="chown $newowner:$newowner"    
for fname in list
do
in="$dirname/$fname"                    
if [[ -e $in  ]]                        
then
     while  read  line
    do
            tmp=$(print "$line"|awk '{if (substr($2,1,1) == "/" )  print $2; if (substr($0,1,1) == "/" )  print '})         
            if [[  -e $tmp  ]]                                                                                     
           then
                    eval  $command \"$tmp\"                                        
             fi
    done < $in
else
        echo "input file $fname is not present. Check file location in the script."
fi
done

【问题讨论】:

  • 我打赌你根本不需要 awk:“列表”文件中有什么?
  • 列表文件和其他几个可以添加到 for 循环的输入文件包含用户留下的文件的报告。我从这些文件中删除文件名,然后尝试更改当前用户对它们的所有权,以便可以管理磁盘。
  • 但是您的 awk 命令表明每行有 2 个字段。那个文件里有什么?这可能是您问题的根源
  • 我没有问题剥离文件。以下是输入文件的示例: 1) 文件名:driver2.ZIP 大小(兆字节):254 位置:/sasdev/dropzone/dm_etl/HB/IRS/2014/AugME/driver2.ZIP /sasdev/dropzone/dm_etl/HB/ IRS/2014/DecME/driver2.ZIP /sasdev/dropzone/dm_etl/HB/IRS/2014/NovME/driver2.ZIP 创建于:2014 年 9 月 3 日
  • 请更新您的问题。你不能用多行格式化评论

标签: ksh chown


【解决方案1】:

其他几个错误:

  • date &gt; $dir$logfile -- 未定义 $dir 变量
  • 安全读取文件:while IFS= read -r line

但要回答您的主要问题,请不要尝试如此动态地构建命令:不要打扰 $command 变量,不要使用 eval,并引用变量。

chmod "$newowner:$newowner" "$tmp"

【讨论】:

  • 谢谢格伦。我按照您的指示简化了 chown 行: chown "$newowner:$newowner" "$tmp" 但我无法创建输出文件,因为 chown 似乎不喜欢输出文件并将所有内容发送到屏幕。 ls -l $logfile >> $output 但是有效。
  • 没有语法错误,但是权限错误。因为我没有根特权。脚本完成后,我将其传递给 root 管理员运行
  • chown:/home/sas/sastest/testdir/mars_auto_score_2010.sas7bdat:不允许操作。 chown: /home/sas/sastest/testdir/Inforce Mart/test_in: 不允许操作。
  • 这显示在屏幕上,我无法将其捕获到文件中。使用 ls 进入输出文件。
  • 那你想让chmod "$newowner:$newowner" "$tmp" 2&gt;"$logfile"捕获错误
【解决方案2】:

eval 去掉了这一行的引号

command="chown $newowner:$newowner"   

为了使该行与空格一起使用,您需要提供反斜杠引号

command="chown \"$newowner:$newowner\""

这样eval实际运行的命令是

chown "$newowner:$newowner"      

此外,您可能需要在此变量设置周围加上引号,尽管您需要调整语法

tmp="$(print "$line"|awk '{if (substr($2,1,1) == "/" )  print $2; if (substr($0,1,1) == "/" )  print '})"

要捕获输出,您可以添加 2>&1 > file.out 其中 file.out 是文件的名称...为了在使用 eval 时使其与它一起使用,您需要反斜杠任何特殊的字符的方式与您需要反斜杠的方式非常相似

【讨论】:

  • 感谢 James 提供的有用的 cmets。我仍然无法将输出发送到输出文件。似乎 chown 不喜欢输出文件并将所有内容发送到屏幕。 ls -l 虽然有效 #chown "$newowner:$newowner" "$tmp" ls -l $logfilepath fi done > $logfilepath
【解决方案3】:

您的示例代码表明该列表是一个“元”文件:一个文件列表,每个文件都有一个要更改的文件列表。当您只有一个文件时,您可以删除 while 循环。
当列表是带有文件名的变量时,您需要echo "${list}"| while ...
不完全清楚为什么有时要从第三个字段开始。似乎有时您在文件名前有 2 个单词并希望它们被忽略。当您的文件名也有空格时,在空格上剪切字符串会成为一个问题。解决方案是寻找一个空格后跟一个斜杠:该空格不是文件名的一部分,并且可以删除该空格之前的所有内容。

newowner=eg27395

# The slash on the end is not really part of the dir name, doesn't matter for most commands
dirname=/home/sas/sastest
logfile=chowner.log
# Add braces, quotes and change dir into dirname
date > "${dirname}/${logfile}"

# Line with command not needed

# Is list an inputfile? It is streamed using "< list" at the end of while []; do .. done
while IFS= read -r fname; do
   in="${dirname}/${fname}"
   # Quotes are important
   if [[ -e "$in"   ]]; then
      # get the filenames with a sed construction, and give it to chmod with xargs
      # The sed construction is made for the situation that in a line with a space followed by a slash
      # the filename starts with the slash
      # sed is with # to avoid escaping the slashes
      # Do not redirect the output here but after the loop.
      sed 's#.* /#/#' "${in}" | xargs chmod ${newowner}:${newowner}
   else
       echo "input file ${fname} is not present. Check file location in the script."
   fi
done < list >> "${dirname}/${logfile}"

【讨论】:

  • 感谢 Walter,非常有用的 cmets。我无法创建输出文件,因为 chown 似乎不喜欢输出文件并将所有内容发送到屏幕。 ls -l $logfile >> $output 但是有效。你在循环结束时建议的输出重定向方式也是如此,我在发布之前尝试过:done > "${dirname}/${logfile}"
  • 我认为你在谈论 chown 的错误信息。它们使用标准错误写入控制台。 Stderr 是流 2,stderr 是流 1。您可以使用2&gt;&amp;1 告诉命令将 stderr 写入与 stdout 相同的位置。确保首先重定向标准输出,所以使用&gt;&gt; "${dirname}/${logfile}" 2&gt;&amp;1
猜你喜欢
  • 2012-05-16
  • 1970-01-01
  • 1970-01-01
  • 2018-06-09
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 2011-07-05
  • 2020-11-14
相关资源
最近更新 更多