BASH-使用LS和通配符的FOR循环

Fab*_*Fab 2 bash wildcard

我的目录包含以下文件:

FILE1_h0_something_1950_other.gz
FILE2_h0_something_1950_other.gz
FILE3_h0_something_1950_other.gz
Run Code Online (Sandbox Code Playgroud)

这是我的bash脚本的一部分:

year=1950
for nc_gz in "$input_path/*h3*$year*.gz"; do
      gunzip $nc_gz
done
Run Code Online (Sandbox Code Playgroud)

我注意到有些时候(奇怪的行为……我总是或永远没有,除非如此)在我的目录中创建了一个名为* h3 * 1950 *的文件。

当目录不包含gz文件时,代码将失败。

问题出在哪里?

谢谢

Gil*_*il' 5

for nc_gz in "$input_path/*h3*$year*.gz"; do
Run Code Online (Sandbox Code Playgroud)

您正在遍历一个元素的列表。由于"$input_path/*h3*$year*.gz"用双引号引起来,所以它是一个字符串。因此,如果input_pathis 的值和is /some/where的值,year则会2017运行一次循环主体,并将其nc_gz设置为/some/where/*h3*2017*.gz

  gunzip $nc_gz
Run Code Online (Sandbox Code Playgroud)

这里$nc_gz未引用,因此将split + glob运算符应用于结果。在上面的示例中,/some/where/*h3*2017*.gz将展开为匹配文件列表;除非没有匹配的文件,否则将gunzip使用参数调用/some/where/*h3*2017*.gz

首先,正确引用:

对于 $ input_path /  * h3 *  $ year  * .gz中的nc_gz ; 做
      gunzip  $ nc_gz 
做完了

如果通配符不匹配任何文件,这仍然会运行一次循环,这是因为外壳功能不匹配的通配符模式保留不变,而不是扩展为空列表。在bash中(但不是普通sh),可以通过设置nullglob选项来避免这种情况。

#!/bin/bash
shopt -o nullglob
for nc_gz in "$input_path/"*h3*"$year"*.gz; do
  gunzip "$nc_gz"
done
Run Code Online (Sandbox Code Playgroud)

简而言之,您可以通过跳过不存在的文件来避免这种情况。

for nc_gz in "$input_path/"*h3*"$year"*.gz; do
  if [ ! -e "$nc_gz" ]; then continue; fi
  gunzip "$nc_gz"
done
Run Code Online (Sandbox Code Playgroud)

请注意,我以为这是简化的代码,您确实需要循环来执行除调用之外的其他事情gunzip。如果您需要做的只是解压缩文件,则可以调用gunzip一次,因为它支持多个文件参数。

gunzip "$input_path/"*h3*"$year"*.gz
Run Code Online (Sandbox Code Playgroud)

这在解压缩文件的意义上起作用,并且如果通配符模式与任何文件都不匹配,则不会执行任何操作,但是gunzip会抱怨不存在的文件。bash的nullglob选项对您没有帮助,因为gunzip没有文件名的调用也不起作用(它希望从其标准输入中解压缩数据)。您需要测试匹配文件的数量。

unzip_matching_files () {
  if [ $# -eq 1 ] && [ ! -e "$1" ]; then return; fi
  gunzip "$@"
}
unzip_matching_files "$input_path/"*h3*"$year"*.gz
Run Code Online (Sandbox Code Playgroud)