为什么我的shell脚本循环比我想要的多?

时间:2018-06-15 15:45:19

标签: bash shell

我正在为我正在建设的管道编写一个shell脚本。代码应该只从目录中获取10个唯一文件标识符的列表,然后开始对它们进行一些分析。代码确实以我抓取的10个文件开头,然后继续在整个目录上运行!代码如下:

第一个基本用户输入

#!/bin/bash

Dir=$1 #needs directory containing the input files

然后将10个唯一标识符放入列表

if [ -e file_list.txt ] #remove any list at the start
then
    rm file_list.txt
fi 
for file in `ls ${Dir}* | cut -f 6 -d '/' | cut -f 1 -d '_' | uniq | head` #grab the first 10 unique files and put them in a text file
do
    echo $file >> file_list.txt #each file set has a unique tag, write that out to the list
done

现在查看文件列表并执行操作

while read file #now iterate through the list of files
do 
    #do stuff to file here
    ls ${file}* #list every file with this tag; just an example
done < file_list.txt 

我想说,当我抓住10个文件名时,罪魁祸首就是调用uniq。在使用uniq之前,此代码的早期版本没有此问题。但我不知道除非这对我的file_list.txt做了一些奇怪的事情,这对我来说很好。

当我处理第三个代码块中的文件时,错误是否存在?

我使用了shellcheck并且我得到了很多注释&#34;双引号以防止通配和分词。&#34;

1 个答案:

答案 0 :(得分:2)

关于&#34;为什么&#34; - 如果不知道你的文件名,几乎不可能说出来。例如,名称前面带有文字*的任何文件都将被原始代码扩展为目录中的每个其他文件的列表。而不是跟踪破坏代码的原因,而是首先编写一些遵循最佳实践的内容更为明智,因此您不需要深入了解不应该使用的功能的蜿蜒路径。从脚本中使用可以在创造不必要的混乱中相互影响。

在我阅读时,您希望根据其名称前第一个_之前的内容为每个文件分配一个标记,然后使用前10个唯一标记获取文件。

我们可以做到这一点。它可能看起来像这样:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*) echo "ERROR: Needs bash 4.0 or later" >&2; exit 1;; esac

Dir=$1

files=( "$Dir"/*_* )            # collect files w/ underscores in our directory in an array
declare -A example_per_tag=( )  # create a map from tag to full filename

for file in "${files[@]}"; do   # iterate over the array of files
  basename=${file##*/}          # take off the directory name to get the basename
  tag=${basename%%_*}           # take off the first _ and everything after to get the tag
  example_per_tag[$tag]=$file   # store a link from that tag to the file in our map
done

# can't slice a list of keys from an associative array, so we need an indexed array w/ them
tags=( "${!example_per_tag[@]}" ) # collect only the keys -- the tags -- in an array

# now, iterate over only the first 10 tags
for tag in "${tags[@]:0:10}"; do
  echo "For tag $tag, our example file is ${example_per_tag[$tag]}"
done

注意这里的所有引用;我们引用的唯一地方是:

  • 在赋值的右侧,或数组查找的索引(两者都是隐式禁用字符串分割和通配的情况)。
  • 对于一个glob表达式(如*_*),我们希望它扩展而不是作为文字处理。