【问题标题】:Shell script interpretation code and parametersShell脚本解释代码和参数
【发布时间】:2018-03-28 16:21:11
【问题描述】:

我有以下 shell 脚本,他们问我如何工作以及 $1 和 $2 参数是什么。

#!/bin/bash

for i in `sort $1`; do   
    if grep $2 $i > /dev/null; then 
        echo A  
        cp $i /tmp  
        exit  
    fi  
done  
echo B;

我的问题是:$1 不能是目录,因为您不能对目录进行排序。因此,它必须是一个文件。但是“for i in file”功能意味着我们将为每一行工作,而“grep”工具不适用于行。

我认为它应该是一个包含文件的文件,但现在我只能想到 tar 文件,它不适用于它们。

谢谢!

【问题讨论】:

  • Don'tReadLinesWithFor -- 这段代码本质上是被破坏的。请参阅 BashFAQ #1 了解有关逐行读取文件的最佳做法。
  • (也就是说,面向行的文件作为一个整体不能安全地用于存储任意文件名的列表,因为文件的名称可以包含换行符。唯一的安全存储适用于任意文件名,例如任意 C 字符串、环境变量等。以 NUL 分隔)。
  • 除此之外,还不清楚您实际上在问什么。是为了解释这段代码的工作原理吗?它不能正常工作——它坏了。 (也比我已经介绍的更多方式 - 如果您的文件中有 * 作为一行,它将被当前工作目录中所有内容的列表替换)。
  • ...你说“我的问题是这个”,但接下来是陈述,而不是问题。
  • 另外,请参阅 Meta StackOverflow 上的 How to deal with questions of the type "I don't understand how this code works?" - 共识是此类问题应以“不清楚您在问什么”或“太宽泛”的方式结束。

标签: bash shell ubuntu


【解决方案1】:

sort $1 很可能意味着$1 包含文件的路径。该文件的内容很可能是其他文件的路径。在其未引用的形式中,它将受到分词和全局扩展的影响。这要么是疏忽,要么是有意的行为(例如,它会将 'dat?.lst' 扩展为文件列表,如 cmets 中所述)。

for 循环假设这些路径都不包含任何尴尬的字符(空格、像 * 这样的全局字符),并遍历排序输出中的每个单词。

$2(实际上应该是"$2")是在文件$i 中搜索的模式。如果文件的内容与模式匹配,则将文件复制到/tmp 并退出脚本。

考虑到不使用包含换行符的文件名的警告,最简单的解决方法是:

#!/bin/bash

sort "$1" | while read -r file; do
    if grep -q "$2" "$file" 2>/dev/null; then
        echo A  
        cp "$file" /tmp  
        exit  
    fi
done

这假定脚本将文件的路径作为第一个参数传递,例如:

/path/to/first/file
/path/to/second/file

还有一个正则表达式作为第二个参数,$s 转义以防止 shell 尝试扩展它们。

【讨论】:

  • $1 还是 "$1" 会改变程序的语义。也许作者想要传递“dat?.lst”作为参数,需要扩展?
  • @userunknown:那将是一个非常尴尬的界面。如果是这种情况,脚本应该处理多个参数,并让 shell 执行 globbing;那么最好重新设计接口,将模式作为第一个参数,其余参数将是文件。然后使用为script thing-to-match file1 file2 file3,并允许script thing-to-match dat?.lst。
  • @userunknown:由于脚本编写者甚至没有为grep 语句引用扩展$2,我认为这更像是脚本编写者的错误,而不是实际的设计功能。
  • @gniourf_gniourf:AFAIK,这个问题是一个面试问题,你应该回答脚本的作用——而不是如何改进它。
【解决方案2】:
!/bin/bash

for i in `sort $1`  
do   
if grep $2 $i > /dev/null  
    then 
         echo A  
         cp $i /tmp  
         exit  
    fi  
done  
echo B;

可能,第一个参数是文件名或不带空格的文件名列表,它本身包含文件名列表。 $2 是在这些文件中搜索的关键字,这些文件首先按名称排序。

第一个匹配导致该文件的副本到 /tmp - 可能用于进一步处理,以及回显消息 A 和程序终止。如果没有找到匹配的文件,则会打印一条不同的消息。

注意,像这样屏蔽 $1:

for i in $(sort "$1")
do   

会阻止通配符的扩展,

script "dat-?.lst" foobar

并且可能会破坏脚本,因此我会谨慎提出改进建议。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2011-11-19
    • 2014-11-27
    • 2023-03-06
    相关资源
    最近更新 更多