Bash避免了intrpretate特殊字符

地狱大家 我在bash中写的脚本有问题。 该脚本负责简单地recursionsearch[path]中[input文件]中给出的模式。 如果没有findpattern,那么它被写入到[OPTIONAL OUTPUT FILE]中。 如果没有给出[OPTIONAL OUTPUT FILE],则默认的[OUTPUT FILE]名称是:out。 问题是具有特殊性质。 (点)这是脚本的代码:

#!/bin/bash #This script is responsible for simply searching recursively patterns given in input file in path where we have to search. If pattern is not found then is written to output file; #@version 1.0 function help() { echo -e "This script is responsible for simply recursively searching patterns\ngiven in [INPUT FILE] in [PATH]. If pattern is not found then it is\nwritten to [OPTIONAL OUTPUT FILE]. If [OPTIONAL OUTPUT FILE] is not\ngiven the default [OUTPUT FILE] name is: out" echo 'Usage: ./search.sh [INPUT FILE] [PATH TO DIRECTORY] [OPTIONAL OUTPUT FILE]' echo 'eg : ./search.sh input_file /var/www/html/ output_file' echo 'or : ./search.sh help -> this help' } in=$1 path=$2 out=${3:-out} if [ $# -lt 2 ]; then help; exit; fi if [ ! -e $in ]; then echo "Input file: $1 does not exist"; exit; fi if [ ! -d $path ]; then echo "Path: $path does not exist"; exit; fi #Delete lines that are either blank or only contain spaces sed -i '/^ *$/d' $in tmp='tmpFile' cat $in | sed -e 's,\\,\\\\,g' | sed -e 's,\",\\\",g' | sed -e 's,-,\\-,g' | sed -e 's/\./\\./g' > $tmp counter=0 #Write each line from input file and save it to array while read line do linesTable[$counter]=$line let counter++ done < $tmp #Clear file echo -n '' > $tmp for line in "${linesTable[@]}" do #Find recursively pattern line in path and save result to array echo "$line" table=($(grep -r -- "$line" $path)) # echo $(grep -r -- "$line" $path) #If array is empty write string to tmp file if [ 0 -eq ${#table[@]} ]; then echo "$line" | tee -a $tmp; fi done #Free memory taken by arrays unset table[@] unset linesTable[@] #Sort and remove repeated strings. Result save to output file sort $tmp | uniq > $out #Remove tmp file rm -f $tmp 

我无法避免shell解释'。' 这里是input文件的内容:

 asdf 1234 ALA MA gtrrr @ % asdf ~i ? + { | ` ( ) . * - ' " "" -- , ; : ~ \\ \ ~~~ printg("asdf\d%d\\\", &g); 

带有文件的path是例如/ home / user / test /在这个path中我有3个文件,例如abc:a)

 dddno asdf asdfasd asdf asd 

b)

 s;dfhiasdf asdf asd fas-- -- 0 asdf- - 

C)

 d dafdf dd re v 1234 v c v 

我在/ home / user / test / out中运行如下脚本:./search.sh。 在输出文件中:out应该是。 (点),但没有。 可以帮我这个。 我在这个地方卡住了。 先谢谢你。


丹尼斯你好 谢谢你的build议。 它确实对我有帮助,但是我还有一些问题:这个脚本的目的是在给定path中的input_file中查找string模式。 所以我想我必须使用grep -F选项并删除部分sedexpression式。

 sed -i '/^ *$/d' "$in" 

但我不知道如何删除全局空白行和空间看起来像你做的。 我试过,但它不工作:

 <"$in" sed -e '/^ *$/d' 

所以我得到我的解决scheme。 第二个问题是你的代码部分(附加到数组)不适合我:

 patterns+=("$line") 

我得到这个错误:

 ./search.sh: line 45: syntax error near unexpected token `"$line"' ./search.sh: line 45: ` patterns+=("$line")' 

我曾尝试使用,但它也不起作用。

 The script now looks like: #!/bin/bash in="$1" path="$2" out=${3:-out} function help() { cat << EOF This script is responsible for simply recursively searching patterns given in [INPUT FILE] in [PATH]. If pattern is not found then it is written to [OPTIONAL OUTPUT FILE]. If [OPTIONAL OUTPUT FILE] is not given the default [OUTPUT FILE] name is: out Usage: $0 [INPUT FILE] [PATH TO DIRECTORY] [OPTIONAL OUTPUT FILE] eg : $0 input_file /var/www/html/ output_file or : $0 help -> this help EOF } #Delete lines that are either blank or only contain spaces function extract_patterns() { sed -i '/^ *$/d' "$in" } function report_missing_patterns() { local pattern for pattern in "$@"; do grep -q -r -F -- "$pattern" "$path" #if [ 0 -ne $? ]; then printf "%s\n" "$pattern"; fi if [ 0 -ne $? ]; then echo "$pattern"; fi done } function process_patterns() { local patterns line counter=0 patterns=() while read -r line; do patterns[$counter]="$line" let counter++ done < "$in" #report_missing_patterns "${patterns[@]}" | sort -u > "$out" report_missing_patterns "${patterns[@]}" | sort -u | tee "$out" } if [ $# -lt 2 ]; then help; exit 1; fi if [ ! -e "$in" ]; then echo "Input file: $in does not exist"; exit 2; fi if [ ! -d "$path" ]; then echo "Path: $path does not exist"; exit 3; fi extract_patterns | process_patterns 

我有评论#report_missing_patterns "${patterns[@]}" | sort -u > "$out" #report_missing_patterns "${patterns[@]}" | sort -u > "$out"

因为我想在屏幕上显示结果并将其redirect到output_file。

我不明白你遇到什么问题。 你的描述真的不清楚。 所以我会提供一些关于简化脚本的一般build议。 如果还不足以解决你的问题,试着拿出一个更清晰的解释。

我很确定这个脚本比它需要的复杂得多。 花几分钟浏览一个命令的文档,看看它的一个选项是否可以帮助你节省数小时的debugging时间。 花几分钟思考脚本的一般结构可以节省数小时的debugging时间。


以下是您可以简化脚本的几种方法。

  • 所有的variablesreplace应该在双引号内 ,即总是写"$foo"而不仅仅是$foo 。 你有时做了,但不是系统的。 总是使用双引号,除非你知道为什么你希望他们在特定情况下。

  • 这里有一个简单的写你的helpfunction的方法; 这就是所谓的“这里的文件”。

     function help() { cat <<EOF This script is responsible for simply recursively searching patterns given in [INPUT FILE] in [PATH]. If pattern is not found then it is written to [OPTIONAL OUTPUT FILE]. If [OPTIONAL OUTPUT FILE] is not given the default [OUTPUT FILE] name is: out Usage: $0 [INPUT FILE] [PATH TO DIRECTORY] [OPTIONAL OUTPUT FILE] eg : $0 input_file /var/www/html/ output_file or : $0 help -> this help EOF } 
  • 给脚本一个非零的退出代码来指示失败

     if [ $# -lt 2 ]; then help; exit 2; fi if [ ! -e "$in" ]; then echo "Input file: $1 does not exist"; exit 2; fi if [ ! -d "$path" ]; then echo "Path: $path does not exist"; exit 2; fi 
  • 修改input文件是令人惊讶的,您可以将仅删除空格的行与删除某些字符前的反斜杠的多个sedexpression式组合在一起。

     <"$in" sed -e '/^ *$/d' -e 's,[-\\".],\\&,g' > "$tmp" 

    然而你在这里执行的引用是奇怪的。 你为什么要引用-" ,这些不是特别的grep ,而不是特别的,这是什么模式的语法?

    如果你的意思是模式是文字string寻找,所有这些工作是不必要的(除了删除只有空白的行):call grep -F

  • 在从$tmp读取行的部分,不需要countervariables,只需追加到数组中。 您还需要将-rparameter passing给内置read ,以便它不会去掉一些反斜杠。

     while read -r line; do linesTable+=("$line") done <"$tmp" 
  • 在模式循环中,将grep的输出存储在一个variables中,但是您所做的只是testinggrep是否匹配。 对于那个使用grep的返回码会更容易(也更快)。 (我也删除了大概从循环debugging输出的东西;你不需要tee追加到文件,只需使用redirect操作符>> 。)

     for line in "${linesTable[@]}"; do grep -q -r -- "$line" "$path" if [ $? -ne 0 ]; then echo "$line" >>"$tmp"; fi done 
  • 脚本结尾处不需要释放内存。 如果这真的是一个更大的脚本的一部分,你应该用local内置语言来声明它们。


这是命令行parsing之后脚本部分的重组版本。 我已经整合了上面概述的本地更改,并使用函数来使结构更清晰。 请注意,更清晰的结构意味着我不需要使用临时文件。 我不知道所产生的脚本是否做了你想要的,因为你没有精确地解释你想要的。

 function extract_patterns () { <"$in" sed -e '/^ *$/d' -e 's,[-\\".],\\&,g' } function report_missing_patterns () { local pattern for pattern in "$@"; do grep -q -r -- "$pattern" "$path" if [ $? -ne 0 ]; then printf "%s\n" "$pattern"; fi done } process_patterns () { local patterns line patterns=() while read -r line; do patterns+=("$line") done report_missing_patterns "${patterns[@]}" | sort -u >"$out" } extract_patterns | process_patterns 

主要的事情:

  • sed逃避一连串的字符
  • 你将需要用variables$tmpreplace它出现在input文件中的地方(你不需要清除它),而是保留它作为输出文件
  • 使用-r和read来保存反斜杠: while read -r line
  • 使用-F (固定string)和grep来防止正则expression式的解释: table=($(grep -F -r -- "$line" "$path"))

补充笔记:

  • 使用linesTable数组并不是必须的,只需要在读取linesTable进行处理
  • 你可以使用sort -u和消除uniq
  • 没有必要取消设置variables,当脚本退出时,shell会为你做这些事情
  • 你并不需要在循环中反复调用外部tee 。 你可以使用另一个echoecho "$line" >> "$tmp"或者把tee放在循环之外,因为你已经有了一个echodone | tee "$tmp" done | tee "$tmp" (那么你不需要-a
  • 你可以通过将循环的输出直接input到sort -u>“$ out”来消除临时文件的最后一次使用,
  • 所有包含文件名的variables都应该被引用
  • table并不需要是一个数组,因为你没有访问单个元素