fgrep包含在ksh脚本中包含空格的字符串

时间:2016-11-04 00:14:42

标签: shell grep ksh

我正在尝试编写一个fgrep语句,删除文件中包含完整记录匹配的记录。我可以在命令行上执行此操作,但不能在ksh脚本中执行此操作。我使用的代码归结为这4行代码:

   Header='abc def|ghi jkl' #I use the head command to populate this variable

   workfile=abc.txt

   command="fgrep -Fxv \'$Header\' $workfile" >$outfile

   $command

当我向STDIN回显$command时,命令就是我在命令行上输入的命令(使用单引号)并且在命令行上有效。当我在ksh脚本(文件)中执行它时,单引号似乎无法被识别,因为错误显示它正在空格上解析。

我已经尝试过ticks,exec,eval,双引号而不是单引号,而不使用$command变量。问题依然存在。

2 个答案:

答案 0 :(得分:2)

  

我可以在命令行上执行此操作,但不能在ksh脚本中执行此操作

这是一个简单,便携,可靠的解决方案,使用 heredoc

#!/usr/bin/env ksh

workfile=abc.txt
outfile=out.txt  

IFS= read -r Header <<'EOF'
abc def|ghi jul
EOF

IFS= read -r command <<'EOF'
grep -Fxv "$Header" "$workfile" > "$outfile"
EOF

eval "$command"

解释

(评论无法添加到上面的脚本中,因为它们会影响 heredoc 中的行

IFS= read -r Header <<'EOF'                   # Line separated literal strings
abc def|ghi jul                               # Set into the $Header variable
EOF                                           # As if it were a text file

IFS= read -r command <<'EOF'                  # Command to execute
grep -Fxv "$Header" "$workfile" > "$outfile"  # As if it were typed into
EOF                                           # the shell command line

eval "$command"                               # Execute the command

以上示例与名为 header.txt 的文本文件相同,其中包含内容:abc def|ghi jul并键入以下命令:

  • grep -Fxvf header.txt abc.txt

heredoc 解决了由于 引用而导致脚本操作与命令行 不同的问题/扩展/逃避问题。

关于eval

的警告

在此示例中使用eval是具体的。有关eval如何被滥用并导致潜在破坏性结果的信息,请参阅Eval command and security issues

更多细节/替代示例:

为了完整性,清晰度和将此概念应用于其他情况的能力,关于 heredoc 的一些注释以及另一种示范:

此示例 heredoc 的此实现是专门根据以下条件设计的:

  • 字面字符串内容分配到变量(使用&#39; EOF&#39;
  • 使用 eval 命令评估和执行heredoc本身内的引用变量。

档案还是heredoc?

使用 heredoc grep -F fgrep)相结合的一个优点是能够将脚本的一部分视为一个文件。

档案案例

  • 你想经常粘贴&#34; pattern&#34;将行放入文件中,并根据需要删除它们,不用修改脚本文件。

heredoc的案例:

  • 您可以在已存在特定文件的环境中应用该脚本,并且希望将特定的文字模式与其匹配。

实施例

  • 场景:我有5个VPS服务器,我想要一个脚本来生成一个新的fstab文件,但确保它不包含确切的行:
  • /dev/xvda1   /               ext3    errors=remount-ro,noatime,barrier=0 0       1

此方案符合此问题中解决的情况类型。我可以在本答案中使用上面代码中的样板文件并按如下方式修改:

#!/usr/bin/env ksh

workfile=/etc/fstab

IFS= read -r Header <<'EOF'
/dev/xvda1  /               ext3    errors=remount-ro,noatime,barrier=0 0       1
EOF

IFS= read -r command <<'EOF'
grep -Fxv "$Header" "$workfile"
EOF

eval "$command"

这会给我一个新的fstab文件,但不包含 heredoc 中包含的行。

答案 1 :(得分:1)

Bash FAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!提供了全面的指导 - 虽然它是为 Bash 编写的,但大多数也适用于 Ksh [1]

如果您想坚持将命令存储在变量中(定义函数是更好的选择),请使用数组,绕过引用问题:

#!/usr/bin/env ksh

Header='abc def|ghi jkl'

workfile=abc.txt

# Store command and arguments as elements of an array
command=( 'fgrep' '-Fxv' "$Header" "$workfile" ) 

# Invoke the array as a command.
"${command[@]}" > "$outfile"

注意:只有简单命令可以存储在数组中,并且重定向不能成为其中的一部分。

[1]函数示例使用local创建局部变量,ksh不支持。忽略local代替shell全局变量,或者使用function <name> {...}语法与typeset代替local来声明ksh中的局部变量。