Bash 索引文件和解析名称

Bash 索引文件和解析名称,bash,shell,filenames,Bash,Shell,Filenames,我有一个目录,/grd\u files/lat36/,其中有7个文件(n36e114.grd,n36e115.grd,n36e116.grd,n36e117.grd,n36e118.grd,n36e119.grd,n36e120.grd。在/grd\u文件/下面还有其他名为lat37,lat38,的文件夹,每个文件夹中都包含一些相同的文件格式与lat36中的格式相同,只是在lat37文件夹中e114经度的文件将被称为n37e114,而不是n36e114.grd。现在,并非所有的lat**文件夹都

我有一个目录,
/grd\u files/lat36/
,其中有7个文件(
n36e114.grd
n36e115.grd
n36e116.grd
n36e117.grd
n36e118.grd
n36e119.grd
n36e120.grd
。在
/grd\u文件/
下面还有其他名为
lat37
lat38
的文件夹,每个文件夹中都包含一些相同的文件格式与
lat36
中的格式相同,只是在
lat37
文件夹中
e114
经度的文件将被称为
n37e114
,而不是
n36e114.grd
。现在,并非所有的lat**文件夹都包含所有经度,但我需要它们

我已经编写了脚本的一部分,以确定哪个lat**文件夹中的列最多(它是
lat36
,有7个经度)。我想将
lat36
文件夹中存在的经度与其他文件夹进行比较,如果另一个文件夹中缺少一列,我会进行比较。我可以处理
if-then
语句,但如何比较bash中的列表让我感到困惑

我想列出
row1
文件夹中的文件名,并将其与其他文件夹中的文件进行比较,但名称不匹配,也不应该匹配——只有名称的列部分会匹配,也应该匹配。到目前为止,我已尝试创建一个文件名数组,然后仅对na的列部分进行解析请注意,这些实际上是地图分幅,因此名称的格式实际上是北距(row)和缓和(col)中的坐标例如,
n36e114.grd
。因此,我想分离名称的所有
e114
样式部分,并检查并确保它们存在于其他行中。我希望这是有意义的。下面是我尝试的内容,但我对bash语法不太了解,所以我很困惑。非常感谢您的帮助。 col_list_raw=($(查找$maxdirectory-name.grd“-exec basename{}.grd\)) col_list=(对于${col_list_raw[@]}中的c;执行回显${col_list_raw[$c]:3:7};完成) 其中,
$maxdirectory
是列数最多的一个。*


更新:我已经删除了上面用斜体字描述的内容,并尝试合并来自John1024的解决方案。下面是代码

cd ./grd_files  
for row in lat*/
    do
        ls "$row"  | sed 's/.*lon/lon/' >"${row%/}.tmp"
done
for f in lat*.tmp
    do
        grep -vFf "$f" ${latXX}.tmp >missing.tmp
        [ -s missing.tmp ] && echo ${f%.tmp} is missing $(cat missing.tmp)
done
cd ..
其中
latXX
是经度最大的文件夹。John1024的第一个循环运行良好,我得到了每个
lat**
文件夹的正确列表,但第二个循环直接比较了列表,返回:

lat37 is missing n36e114.grd n36e115.grd n36e116.grd n36e117.grd n36e118.grd n36e119.grd n36e120.grd
lat38 is missing n36e114.grd n36e115.grd n36e116.grd n36e117.grd n36e118.grd n36e119.grd n36e120.grd
lat39 is missing n36e114.grd n36e115.grd n36e116.grd n36e117.grd n36e118.grd n36e119.grd n36e120.grd
我需要这个循环来只比较文件名的一部分。也就是说,我想检查每个文件夹是否存在每个经度。这样,如果文件'n37e114.grd'存在,什么也不会发生,但如果它不存在,则返回该信息,我可以根据丢失的文件执行命令。我希望我的编辑清除了命名约定,并且不受影响德斯坦德。再次感谢你的帮助。我是


解决方案:

多亏@John1024的帮助,我找到了一个解决方案。我复制了下面的最终解决方案。接下来,我读入*.out文件,并对其中的每一行执行命令

cd ./grd_files  
for lat in */
    do
    ls "$lat" | sed 's/[a-z][1-9][1-9].*\([a-z][0-9][0-9]*\).grd/\1/' >"${lat%/}.tmp"
done
for file in *.tmp
    do
    lat=$(echo $file | awk -F "." '{print $1}')
    grep -vFf "$file" ${xXX}.tmp >${lat}missing.out
    [ -s ${lat}missing.out ] && echo ${file%.tmp} is missing $(cat ${lat}missing.out)
done

这个问题包括两种不同的文件命名方案。两者的工作原理相同,但为了保持简单直观,这个答案使用了第一种方案

可以通过bash数组循环查找缺少的列。但是,
grep
非常适合此任务,大大简化了逻辑,并且,如果有许多列和行,可能会更快。使用
grep

cd ./grd_files
for row in row*/
do
    ls "$row"  | sed 's/.*col/col/' >"${row%/}.tmp"
done
for f in row*.tmp
do
    grep -vFf "$f" row1.tmp >missing.tmp
    [ -s missing.tmp ] && echo ${f%.tmp} is missing $(cat missing.tmp)
done
上面的第一个循环创建存在于每行中的列的列表。这些列表保存在名为row1.tmp、row2.tmp等的临时文件中

第二个循环将这些列表与参考行row1.tmp进行比较。该行缺少的列列表保存在临时文件missing.tmp中。如果missing.tmp的大小为非零,则会缺少列并生成报告

对于清理,可能需要删除tmp文件。如果是,请在脚本末尾添加以下行:

rm row*.tmp missing.tmp
爱好者版 使用进程替换,可以消除对许多临时文件的需要:

trap "rm missing.tmp" EXIT
for row in row*/
do
    ls row1/  | sed 's/.*col/col/' | grep -vFf <(ls "$row"  | sed 's/.*col/col/') >missing.tmp
    [ -s missing.tmp ] && echo $row is missing $(cat missing.tmp)
done

正如我在评论中告诉你的,提供测试数据是一个很好的实践。在这种情况下,如果提供一个脚本来创建测试用例,你会得到更多的答案,比如:

mkdir grid
cd grid
mkdir lat3{5..9}
    #if you don't know the {3..9} expansion, simply write
    #mkdir lat36 lat37 lat38 lat39
touch lat35/n35e111.grd
touch lat36/n36e11{4..9}.grd lat36/n36e120.grd
touch lat37/n37e11{4,6,8}.grd
touch lat38/n38e11{4..9}.grd
#39 missing all files
创建一个测试用例所需的脚本比整页文字更有用。;)或者,如果没有脚本,至少提供
find
的输出,比如
find grid-print
。您的第一次编辑对@John1024的工作有点帮助,(我错过了它)并且+100

现在谈谈解决办法

您的最终解决方案有一个问题。如果经度最大的目录(您的LATX)缺少一些其他目录中存在的gridfile怎么办?例如,它有最多的gridfile,但仍然不是全部。与上面的测试案例一样,
lat36
包含7个文件(大部分),但缺少一个文件
n36e111.grd
(因为111只存在于lat35中)

因此,我创建了一个替代解决方案,它消除了这个问题,并将结果显示为下一个矩阵:

    111 114 115 116 117 118 119 120
35: +   no  no  no  no  no  no  no      # the 111 is here
36: no  +   +   +   +   +   +   +       # the dir with a MOST of longitudes but missing 111
37: no  +   no  +   no  +   no  no
38: no  +   +   +   +   +   +   no
39: no  no  no  no  no  no  no  no      # missing all longitudes
剧本

start="./test/grid"
cd "$start" || err "can cd to $start" || exit 1

known_longs=$(find . -type f -name \*.grd -print | sed 's:.*/n.*e\([0-9][0-9]*\)\.grd:\1:' | sort -u)
known_lats=$(find . -type d -print | grep -oP 'lat\K\d+(?=/?)' | sort -u)

print_matrix() {
    echo -ne "\t"
    paste -s - <<<"$known_longs"
    for lat in $known_lats
    do
        echo -en "$lat:"
        for long in $known_longs
        do
            [[ -e "./lat${lat}/n${lat}e${long}.grd" ]] && echo -en "\t+" || echo -en "\tno"
        done
        echo
    done
}
print_matrix
对于丢失的文件,执行一个操作(回显丢失的内容),然后输出:

from lat35 missing n35e114.grd
from lat35 missing n35e115.grd
from lat35 missing n35e116.grd
from lat35 missing n35e117.grd
from lat35 missing n35e118.grd
from lat35 missing n35e119.grd
from lat35 missing n35e120.grd
from lat36 missing n36e111.grd
from lat37 missing n37e111.grd
from lat37 missing n37e115.grd
from lat37 missing n37e117.grd
from lat37 missing n37e119.grd
from lat37 missing n37e120.grd
from lat38 missing n38e111.grd
from lat38 missing n38e120.grd
from lat39 missing n39e111.grd
from lat39 missing n39e114.grd
from lat39 missing n39e115.grd
from lat39 missing n39e116.grd
from lat39 missing n39e117.grd
from lat39 missing n39e118.grd
from lat39 missing n39e119.grd
from lat39 missing n39e120.grd
当然,有可能进行更多优化,例如:

  • 只查找一次(如果目录树很大,则会有帮助-通过
    find命令创建文件名列表
  • 不要测试每个文件,而是测试文件名是否存在于先前创建的文件名列表中
比如在下一个

startdir="./test/grid"
(cd "$startdir" || err "can cd to $start" || exit 1

gridlist="/tmp/griglist.$$"
trap "rm -f $gridlist;exit" 0 2

find . -regex '\./lat[0-9][0-9]*.*' -print >$gridlist
known_longs=($(sed -n 's:^.*/n[0-9][0-9]*e\([0-9][0-9]*\)\.grd$:\1:p' $gridlist | sort -u))
known_lats=($(grep -oP '/lat\K\d+((?=/?)|$)' $gridlist | sort -u))

full_list() {
    for lat in ${known_lats[@]}
    do
        for long in ${known_longs[@]}
        do
            echo "./lat${lat}/n${lat}e${long}.grd"
        done
    done
}
comm -13 $gridlist <(full_list)) | while read missing
do
    #do something with the miising file
    echo "$missing"
done
startdir=“/测试/网格”
(cd“$startdir”| | err”可以cd到$start“| |出口1
gridlist=“/tmp/griglist.$$”
陷阱“rm-f$gridlist;退出”0 2
查找.-regex'\./lat[0-9][0-9]*.'-print>$gridlist
已知长度=($(sed-n's:^.*/n[0-9][0-9]*e\([0-9][0-9]*\)\。grd$:\1:p'$gridlist | sort-u))
已知值=($(grep-o)
from lat35 missing n35e114.grd
from lat35 missing n35e115.grd
from lat35 missing n35e116.grd
from lat35 missing n35e117.grd
from lat35 missing n35e118.grd
from lat35 missing n35e119.grd
from lat35 missing n35e120.grd
from lat36 missing n36e111.grd
from lat37 missing n37e111.grd
from lat37 missing n37e115.grd
from lat37 missing n37e117.grd
from lat37 missing n37e119.grd
from lat37 missing n37e120.grd
from lat38 missing n38e111.grd
from lat38 missing n38e120.grd
from lat39 missing n39e111.grd
from lat39 missing n39e114.grd
from lat39 missing n39e115.grd
from lat39 missing n39e116.grd
from lat39 missing n39e117.grd
from lat39 missing n39e118.grd
from lat39 missing n39e119.grd
from lat39 missing n39e120.grd
startdir="./test/grid"
(cd "$startdir" || err "can cd to $start" || exit 1

gridlist="/tmp/griglist.$$"
trap "rm -f $gridlist;exit" 0 2

find . -regex '\./lat[0-9][0-9]*.*' -print >$gridlist
known_longs=($(sed -n 's:^.*/n[0-9][0-9]*e\([0-9][0-9]*\)\.grd$:\1:p' $gridlist | sort -u))
known_lats=($(grep -oP '/lat\K\d+((?=/?)|$)' $gridlist | sort -u))

full_list() {
    for lat in ${known_lats[@]}
    do
        for long in ${known_longs[@]}
        do
            echo "./lat${lat}/n${lat}e${long}.grd"
        done
    done
}
comm -13 $gridlist <(full_list)) | while read missing
do
    #do something with the miising file
    echo "$missing"
done