使用子shell将参数替换为diff

use*_*023 1 bash shell

我正在编写一个shell脚本,并且为了使它更简单易读,我试图使用嵌套的子shell将参数传递给diff.

这就是我所拥有的:

if
  diff -iy '$(sort '$(awk 'BEGIN { FS = "|" } ; {print $1}' new-participants-by-state.csv)' '$(awk 'BEGIN { FS = "|" } ; {print $1}' current-participants-by-state.csv)')' > /dev/null;
then  
  echo There is no difference between the files. > ./participants-by-state-results.txt;
else  
  diff -iy '$(sort '$(awk 'BEGIN { FS = "|" } ; {print $1}' new-participants-by-state.csv)' '$(awk 'BEGIN { FS = "|" } ; {print $1}' current-participants-by-state.csv)')' > ./participants-by-state-results.txt;
fi
Run Code Online (Sandbox Code Playgroud)

当我运行脚本时,我会继续 diff: extra operand 'AL'

我很欣赏任何有关为什么失败的见解.我觉得我很亲密.谢谢!

Jon*_*ler 5

你的代码是不可读的,因为这些行很长:

if diff -iy '$(sort '$(awk 'BEGIN { FS = "|" } ; {print $1}' new-participants-by-state.csv)' \
       '$(awk 'BEGIN { FS = "|" } ; {print $1}' current-participants-by-state.csv)')' \
       > /dev/null;
then  
    echo There is no difference between the files. > ./participants-by-state-results.txt;
else  
   diff -iy '$(sort '$(awk 'BEGIN { FS = "|" } ; {print $1}' new-participants-by-state.csv)' \
      '$(awk 'BEGIN { FS = "|" } ; {print $1}' current-participants-by-state.csv)')' \
      > ./participants-by-state-results.txt;
fi
Run Code Online (Sandbox Code Playgroud)

重复这样的整个命令也是相当讨厌的.您使用单引号也存在重大问题; 你在每组命令中只有一种,显然是在两个相同awk命令的组合输出上运行(而你可能需要两个独立的排序,一个用于每个awk命令的输出); 你什么时候没有使用这个-F选项awk; 你正在重复这个地方庞大的文件名; 最后,看起来你可能想要使用进程替换,但实际上并没有这样做.

让我们退后一步,明确地提出问题.

  • 给定两个文件(new-participants-by-state.csvcurrent-participants-by-state.csv)在每个文件的每一行上找到第一个管道分隔字段,对这些字段的列表进行排序,并比较两个排序列表的结果.
  • 如果没有差异,请在输出文件中写入一条消息participants-by-state-results.txt; 否则,列出输出文件中的差异.

所以,我们可以使用:

oldfile='current-participants-by-state.csv'
newfile='new-participants-by-state.csv'
outfile='participants-by-state-results.txt'

tmpfile=${TMPDIR:-/tmp}/xx.$$

awk -F'|' '{print $1}' $oldfile | sort > $tmpfile.1
awk -F'|' '{print $1}' $newfile | sort > $tmpfile.2

if diff -iy $tmpfile.1 $tmpfile.2 > $outfile
then echo "There is no difference between the files" > $outfile
fi

rm -f $tmpfile.?
Run Code Online (Sandbox Code Playgroud)

如果这将是最终的脚本,我们希望将陷阱处理放在适当的位置,以便除非脚本被SIGKILL杀死,否则不会留下临时文件.

但是,我们现在可以使用进程替换来避免临时文件:

oldfile='current-participants-by-state.csv'
newfile='new-participants-by-state.csv'
outfile='participants-by-state-results.txt'

if diff -iy <(awk -F'|' '{print $1}' $oldfile | sort) \
            <(awk -F'|' '{print $1}' $newfile | sort) > $outfile
then echo "There is no difference between the files" > $outfile
fi
Run Code Online (Sandbox Code Playgroud)

请注意代码如何在存在对称性的情况下仔细保留对称性.请注意使用短变量名称以避免重复长文件名.请注意,该diff命令只运行一次,而不是两次 - 丢弃以后需要的结果不是很明智.

您可以使用以下方法压缩输出I/O重定向:

{
if diff -iy <(awk -F'|' '{print $1}' $oldfile | sort) \
            <(awk -F'|' '{print $1}' $newfile | sort)
then echo "There is no difference between the files"
fi
} > $outfile
Run Code Online (Sandbox Code Playgroud)

这会将附带命令的标准输出发送到文件.

当然,如果文件是以管道分隔而不是以逗号分隔的,则CSV可能不是合适的术语,但这完全是另一回事.

我也假设diff -iy原始脚本建议的状态是起作用的; 我没有验证该diff命令的用法.