我正在尝试编写一个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
变量。问题依然存在。
答案 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 的此实现是专门根据以下条件设计的:
使用 heredoc 与 grep -F (fgrep
)相结合的一个优点是能够将脚本的一部分视为一个文件。
档案案例
heredoc的案例:
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
中的局部变量。