【问题标题】:How to use `diff` on files whose paths contain whitespace如何在路径包含空格的文件上使用 `diff`
【发布时间】:2017-04-06 09:10:24
【问题描述】:

我试图找出文件之间的差异,但文件名和目录名包含空格。我正在尝试在 Perl 脚本中执行命令。

diff /home/users/feroz/logs/back_up20161112/Security File/General Security.csv /home/users/feroz/logs/back_up20161113/Security File/General Security.csv

Perl

open( my $FH, '>', $logfile ) or die "Cannot open the file '$logfile' $!";

foreach $filename ( keys %filenames ) {

    $old_file = $parent_directory . $previous_date . $search_directory . "$filenames{$filename}";
    $new_file = $parent_directory . $current_date . $search_directory . "$filenames{$filename}";

    if ( !-e $old_file ) {

        #print ("\nFile does not exist in previos date backup");

        print $FH "\nERROR:'$old_file' ---- does not exist in the backup directory ";
    }
    elsif ( !-e $new_file ) {

        #print ("\n The file does not exist in current directory");

        print $FH "\nERROR:'$new_file' --- does not exist in the present directory ";
    }
    else {

        # print $FH "\nDifference between the files $filenames{$filename} of  $previous_date and $current_date ";

        my $cmd = 'diff $old_file $new_file| xargs -0';
        open( my $OH, '|-', $cmd ) or die "Failed to read the output";
        while ( <OH> ) {
            print $FH "$_";
        }
        close $OH;
    }
}

【问题讨论】:

  • diff 不是 Perl 命令。请出示您的真实代码。
  • diff 不是 perl 命令。我正在尝试在 perl 脚本中执行 unix 命令。我提到了 perl 脚本来检查我们是否有任何选项来忽略空白
  • @ferozalam_82:这不相关。请出示您的真实 Perl 代码。
  • 这是我的 perl 代码
  • 我什至尝试过 unix 的选项 xargs 选项,我不知道它是否有效

标签: linux perl shell unix


【解决方案1】:

为了绝对安全,请使用 ShellQuote

use String::ShellQuote;

my $old_file2 = shell_quote($old_file);
my $new_file2 = shell_quote($new_file);
`diff $old_file2 $new_file2`;

【讨论】:

  • 只要为提供/bin/sh 的shell 正确实现了String::ShellQuote,这与我的答案(任何一个分支)一样安全。 +1。
【解决方案2】:

感谢您展示您的 Perl 代码

单引号不会插入,因此会将字符串 $old_file$new_file 传递给命令,而不是那些变量的内容。然后 shell 会尝试将它们解释为 shell 变量

我建议你改写这个

my $cmd = qq{diff '$old_file' '$new_file' | xargs -0};
open( my $OH, '-|', $cmd ) or die "Failed to read the output";

这将在命令字符串周围使用双引号 (qq{...}),以便对变量进行插值。文件路径有单引号,表示 shell 应将它们视为单独的字符串

如果您的文件路径可能包含单引号,这将不起作用,但这是非常不寻常的

【讨论】:

  • 考虑故意攻击的情况——即。使用touch $'$(rm -rf $HOME)\'$(rm -rf $HOME)\'.txt' 创建的文件作为参数传递给(或被迭代)此脚本。似乎教授这种技术就是在教授如何制造安全漏洞。
【解决方案3】:

将参数带外传递以避免需要对它们进行 shell 引用,而不是将它们插入到由 shell 作为脚本解析的字符串中。将文件名作为文本替换到脚本中会导致 shell injection attacks 暴露——这种 shell 脚本等同于被称为 SQL injection 的数据库安全漏洞系列。


完全没有外壳

xargs -0 的管道在这里似乎没有用。消除它可以在不涉及任何 shell 的情况下运行它:

open(my $fh, "-|", "diff", $old_file, $new_file)

Shell 参数从脚本文本带外传递

如果您确实希望调用 shell,安全的做法是将脚本文本保持为经过审核的常量,并让它从传递给 shell 或环境的 argv 列表中检索参数。

# Putting $1 and $2 in double quotes ensures that the shell treats contents as literal
# the "_" is used for $0 in the shell.
$shell_script='diff "$1" "$2" | xargs -0'
open(my $fh, "-|",
  "sh", "-c", $shell_script,
  "_", $old_file, $new_file);

【讨论】:

  • +1 获得绕过外壳的唯一答案; -1 表示您的答案中的外壳绕过看起来像是事后的想法......
  • @oals,OP 的请求涉及运行管道;因此,shell 绕过方法不一定是真正响应式的,除非它被分解为多个分支。
  • 我知道,但 xargs 似乎是 OP 的错误添加;至少对我来说是零意义。
  • @oals, ...重新排序,明确调用了无外壳方法。更好?
  • 是的,非常如此。
【解决方案4】:

你可以

  1. 将空格路径段放在引号内

    diff /home/users/feroz/logs/back_up20161112/"Security File"/General Security.csv /home/users/feroz/logs/back_up20161113/"Security File"/General Security.csv
    
  2. 或转义空格

    diff /home/users/feroz/logs/back_up20161112/Security\ File/General Security.csv /home/users/feroz/logs/back_up20161113/Security\ File/General Security.csv`
    

【讨论】:

  • 我们有没有其他选项可以在不手动编辑的情况下忽略空白?
  • @ferozalam_82,嗯,理想要做的事情是调用外部程序而不涉及 shell,直接传递一个 argv 数组,然后传递给 @ 987654324@-family 系统调用启动程序。
猜你喜欢
  • 1970-01-01
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 2011-05-19
  • 2011-04-13
  • 1970-01-01
相关资源
最近更新 更多