简体   繁体   English

循环遍历目录中的每个文件 - bash

[英]Looping through each file in directory - bash

I'm trying to perform certain operation on each file in a directory but there is a problem with order it's going through.我正在尝试对目录中的每个文件执行某些操作,但是它执行的顺序存在问题。 It should do one file at the time.它应该一次做一个文件。 The long line (unzipping, grepping, zipping) works fine on a single file without a script, so there is a problem with a loop.长行(解压缩、grepping、压缩)在没有脚本的单个文件上运行良好,因此循环存在问题。 Any ideas?有任何想法吗?

Script should grep through through each zipped file and look for word1 or word2.脚本应该遍历每个压缩文件并查找 word1 或 word2。 If at least one of them exist then:如果至少存在其中之一,则:

  1. unzip file解压文件
  2. grep word1 and word2 and save it to file_done grep word1 和 word2 并将其保存到 file_done
  3. remove unzipped file删除解压文件
  4. zip file_done to /donefiles/ with original name使用原始名称将 file_done 压缩到 /donefiles/
  5. remove file_done from original directory从原始目录中删除 file_done
    #!/bin/bash
    for file in *.gz; do
    counter=$(zgrep -c 'word1\|word2' $file)
    if [[  $counter -gt 0 ]]; then
    echo $counter
    for file in *.gz; do
    filenoext=${file::-3}
    filedone=${filenoext}_done
    echo $file
    echo $filenoext
    echo $filedone
    gunzip  $file | grep 'word1\|word2'  $filenoext > $filedone | rm -f $filenoext |  gzip -f  -c  $filedone > /donefiles/$file | rm -f $filedone
    done
    else
    echo "nothing to do here"
    fi
    done

The code snipped you've provided has a few problems, eg unneeded nested for cycle and erroneous pipeline (the whole line gunzip $file | grep 'word1\\|word2' $filenoext > $filedone | rm -f $filenoext | gzip... ).您提供的代码片段有一些问题,例如循环和错误管道不需要嵌套(整行gunzip $file | grep 'word1\\|word2' $filenoext > $filedone | rm -f $filenoext | gzip... )

Note also your code will work correctly only if *.gz files don't have spaces (or special characters) in names.另请注意,仅当 *.gz 文件名称中没有空格(或特殊字符)时,您的代码才能正常工作。 Also zgrep -c 'word1\\|word2' will also match strings like line_starts_withword1_orword2_ .此外, zgrep -c 'word1\\|word2'也将匹配line_starts_withword1_orword2_字符串。

Here is the working version of the script:这是脚本的工作版本:

#!/bin/bash
for file in *.gz; do
        counter=$(zgrep -c -E 'word1|word2' $file) # now counter is the number of word1/word2 occurences in $file
        if [[ $counter -gt 0 ]]; then
                name=$(basename $file .gz)
                zcat $file | grep -E 'word1|word2' > ${name}_done
                gzip -f -c ${name}_done > /donefiles/$file
                rm -f ${name}_done
        else
                echo 'nothing to do here'
        fi
done

What we can improve here is:我们在这里可以改进的是:

  • since we unzipping the file anyway to check for word1|word2 presence, we may do this to temp file and avoid double-unzipping由于我们无论如何都要解压缩文件以检查 word1|word2 是否存在,因此我们可以对临时文件执行此操作并避免双重解压缩
  • we don't need to count how many word1 or word2 is inside the file, we may just check for their presence我们不需要计算文件中有多少 word1 或 word2,我们可以只检查它们的存在
  • ${name}_done can be a temp file cleaned up automatically ${name}_done 可以是自动清理的临时文件
  • we can use while cycle to handle file names with spaces我们可以使用while循环来处理带空格的文件名
#!/bin/bash
tmp=`mktemp /tmp/gzip_demo.XXXXXX` # create temp file for us
trap "rm -f \"$tmp\"" EXIT INT TERM QUIT HUP # clean $tmp upon exit or termination
find . -maxdepth 1 -mindepth 1 -type f -name '*.gz' | while read f; do
        # quotes around $f are now required in case of spaces in it
        s=$(basename "$f") # short name w/o dir
        gunzip -f -c "$f" | grep -P '\b(word1|word2)\b' > "$tmp"
        [ -s "$tmp" ] && gzip -f -c "$tmp" > "/donefiles/$s" # create archive if anything is found
done

It looks like you have an inner loop inside the outer one :看起来您在外部循环中有一个内部循环:

#!/bin/bash
for file in *.gz; do
    counter=$(zgrep -c 'word1\|word2' $file)
    if [[  $counter -gt 0 ]]; then
        echo $counter
        for file in *.gz; do #<<< HERE
            filenoext=${file::-3}
            filedone=${filenoext}_done
            echo $file
            echo $filenoext
            echo $filedone
            gunzip  $file | grep 'word1\|word2'  $filenoext > $filedone | rm -f $filenoext |  gzip -f  -c  $filedone > /donefiles/$file | rm -f $filedone
        done
    else
        echo "nothing to do here"
    fi
done

The inner loop goes through all the files in the directory if one of them contains file1 or file2.如果其中一个文件包含 file1 或 file2,则内部循环遍历目录中的所有文件。 You probably want this :你可能想要这个:

#!/bin/bash
for file in *.gz; do
    counter=$(zgrep -c 'word1\|word2' $file)
    if [[  $counter -gt 0 ]]; then
        echo $counter
        filenoext=${file::-3}
        filedone=${filenoext}_done
        echo $file
        echo $filenoext
        echo $filedone
        gunzip  $file | grep 'word1\|word2'  $filenoext > $filedone | rm -f $filenoext |  gzip -f  -c  $filedone > /donefiles/$file | rm -f $filedone
    else
        echo "nothing to do here"
    fi
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM