Bash unix查找命令错误
我的命令如下所示:Bash unix查找命令错误,bash,unix,find,Bash,Unix,Find,我的命令如下所示: P8.1 ~basicsys/win15/ex8/d1 cd 3 D A X F1 B #!/bin/sh dir="$1" shift line="$1" shift str="$1" shift for file in "$@"; do find "$dir" -type f -name "$file" -exec awk -v f="$file" -v l="$line" -v s="$str" -v c=0 'FNR == l { if(index($
P8.1 ~basicsys/win15/ex8/d1 cd 3 D A X F1 B
#!/bin/sh
dir="$1"
shift
line="$1"
shift
str="$1"
shift
for file in "$@"; do
find "$dir" -type f -name "$file" -exec awk -v f="$file" -v l="$line" -v s="$str" -v c=0 'FNR == l { if(index($0, s)) { ++c } nextfile } END { print f " " c }' '{}' +
done
所以我有三个参数:dir(保存目录)str(我正在寻找的字符串)num(行号)
我需要做的是检查文件并检查str是否出现在num行中
我需要打印如下内容:
[文件][str出现在目录树中某处的第num行的次数]
输出:
A 1
B 3
D 2
F1 1
X 0
通过调试,我发现我在执行find
命令时遇到了问题
这是我的代码:
dir=$1
shift
str=$1
shift
num=$1
shift
echo 'head -$num | tail -1' >| getLine
echo -n "" >| out
chmod +x getLine
while [ $# -gt 0 ]
do
echo -n $1 " " >> out
find $dir -type f -name $1 -exec getLine {} \; >| tmp
egrep -c $str tmp >> out
shift
done
sort out
也许问题也出在echo'head-$num | tail-1'
请参阅帮助:/
谢谢 我认为问题在于
getLine
脚本没有使用它的参数。它可能与
# also, variable expansion does not work in '' strings, like the comments noted.
echo "head -\"$num\" \"$1\" | tail -1" >| getLine
然而,我觉得这种方法相当丑陋。我会用awk这样做:
P8.1 ~basicsys/win15/ex8/d1 cd 3 D A X F1 B
#!/bin/sh
dir="$1"
shift
line="$1"
shift
str="$1"
shift
for file in "$@"; do
find "$dir" -type f -name "$file" -exec awk -v f="$file" -v l="$line" -v s="$str" -v c=0 'FNR == l { if(index($0, s)) { ++c } nextfile } END { print f " " c }' '{}' +
done
这有两个关键组件:一个是find
调用中的+
使其一次性将所有匹配文件传递给awk命令(有关精确的语义,请参阅find
手册页)。另一个是awk脚本:
FNR == l { # if the line is the lth in the file we're processing
if(index($0, s)) { # and s is a substring of the line
++c # increase the counter
}
nextfile # short-circut to next file. This may fail with old versions
# of awk; it was introduced to the POSIX standard in 2012.
# It can be removed in that case, although that will make
# the script run more slowly (because it'll scan every file
# to the end)
}
END { # at the very end
print f " " c # print the results.
}
此处,l
、s
和f
通过-v
选项设置为主脚本中的用户定义值。首先
您必须用双引号替换引号“
”,才能看到变量$num
展开
不要使用head | tail
,而是尝试sed
:
我的目的(使用纯):
没有分叉和临时文件
!/bin/bash
dir=$1 str=$2 num=$3
班次3
名副其实
计数=0
在读取文件时;执行以下操作:
mapfile-s$[num-1]-tn 1 lineNum用双引号替换引号“
”
,以便看到变量$num
展开!你可以使用sed$num'q;d'
代替头|尾-n1
@F.Hauri谢谢!!!加上它作为答案,我会接受的,兄弟!类似于:find$dir-typef-name$1-execsed$num'q;d'{}\
什么可以包含$str
变量和“一行”(看起来像什么?out
是什么?$num
由用户控制。如果用户没有输入一个数字,这可能会以各种令人惊讶的方式打破。将未初始化的shell变量替换为sed代码已经够糟糕的了,但这甚至超出了双引号的shell字符串。@Wintermute您是对的,但由于在处理之前对条目进行清理可能会更好,因此可以使用相同的语法。当然,sed“${num}q;d”
也会起作用,但对于示例,如果用户点击w/etc/passwd;2
对于$num
,使用双引号只会有助于此攻击尝试…我的一般方法/建议是:当您试图将shell变量放入sed代码中时,尝试使用awk-v var=“$var”
;它只会在类型不匹配时出错,而且在脚本语言中,您将尽可能安全。Sed可能比awk更性感,但不管你从哪个角度看,用户可修改的代码都很讨厌,而且Sed能做的很多/大部分事情都很容易翻译成awk。缺少的背景有时令人烦恼,但这并不需要它们。在这种情况下,awk-v line=“$num”'FNR==line'
的作用与sed相同,“$num q;d”
@Wintermutesed
比awk
快得多。对于许多调用,它可能变得很重要。排除特殊情况,正确性比速度更重要。老实说,当性能变得至关重要时,关键是停止编写shell脚本。