bash 脚本导航目录子结构,然后对 .xml 文件进行操作

Posted

技术标签:

【中文标题】bash 脚本导航目录子结构,然后对 .xml 文件进行操作【英文标题】:bash script to navigate directory substructure and then operate on .xml files 【发布时间】:2015-04-12 10:31:51 【问题描述】:

我厌倦了这个:

for dir in /home/matthias/Workbench/SUTD/nytimes_corpus/NYTimesCorpus/2007/02/*/
    for f in *.xml ; do
        echo $f | grep -q '_output\.xml$' && continue # skip output files
        g="$(basename $f .xml)_output.xml"
        java -mx600m -cp /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/stanford-ner-3.5.1.jar edu.stanford.nlp.ie.crf.CRFClassifier -loadClassifier /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/classifiers/english.all.3class.distsim.crf.ser.gz -textFile $f -outputFormat inlineXML > $g
    done
done

这是基于对this question 的回答,但这不起作用。

我有一个文件夹结构,这样在目录NYTimesCorpus 中有一个目录2007,在里面有一个目录01,还有0203,等等......

然后在01 内又有01,02,03,...

在这些终端目录中的每一个中都有许多我想要应用脚本的 .xml 文件:

for f in *.xml ; do
    echo $f | grep -q '_output\.xml$' && continue # skip output files
    g="$(basename $f .xml)_output.xml"
    java -mx600m -cp /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/stanford-ner-3.5.1.jar edu.stanford.nlp.ie.crf.CRFClassifier -loadClassifier /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/classifiers/english.all.3class.distsim.crf.ser.gz -textFile $f -outputFormat inlineXML > $g
done

但是有这么多不同的目录,在每个目录中运行它是一种罕见的折磨。除了2007,我还有20062005,所以理想情况下我想做的就是运行它一次,然后让程序自行导航该结构。

到目前为止,我的尝试还没有成功,也许你们中的某个人知道如何实现这一目标?

感谢您的考虑。

更新

textFile=./scrypt.sh
outputFormat=inlineXML
Loading classifier from /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/classifiers/english.all.3class.distsim.crf.ser.gz ... done [2.2 sec].
CRFClassifier tagged 71 words in 5 documents at 959.46 words per second.
CRFClassifier invoked on Sun Apr 12 19:33:34 HKT 2015 with arguments:
   -loadClassifier /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/classifiers/english.all.3class.distsim.crf.ser.gz -textFile ./scrypt.sh -outputFormat inlineXML
    loadClassifier=/home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/classifiers/english.all.3class.distsim.crf.ser.gz

【问题讨论】:

【参考方案1】:

我会使用find,因为它递归地工作:

find /path/to/xmls -type f ! -name '*_output.xml' -name '*.xml' -exec ./script.sh  \;

为了更好的可读性,我会将应该对每个文件执行的操作保存到script.sh

#!/bin/bash

f="$1"
g="$f%%.*_output.xml"
java -mx600m -cp /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/stanford-ner-3.5.1.jar edu.stanford.nlp.ie.crf.CRFClassifier -loadClassifier /home/matthias/Workbench/SUTD/nytimes_corpus/NER/stanford-ner-2015-01-30/classifiers/english.all.3class.distsim.crf.ser.gz -textFile "$f" -outputFormat inlineXML > "$g"

并使其可执行:

chmod +x script.sh

【讨论】:

所以在 /path/to/xmls 我必须指定每个目录吗? 所以/path/to/xmls 可以只是相对的根目录,即/home/matthias/Workbench/SUTD/nytimes_corpus/ 是吗? 是的,在您的示例中,这应该是正确的路径 我刚试过,但没有用。我收到了错误Exception in thread main edu.stanford.nlp.io.RuntimeIOException: java.io.FileNotFoundException: *.xml (No such file or directory) find /path/to/xmls -type f -name '*.xml' 的输出是什么?【参考方案2】:

find 是一个很好的解决方案。听起来所有的 xml 文件都在相同的目录深度,所以试试这个:

dir=/home/matthias/Workbench/SUTD/nytimes_corpus
for f in $dir/NYTimesCorpus/*/*/*/*.xml; do
    [[ $f == *_output.xml ]] && continue # skip output files
    g="$f%.xml_output.xml"
    java -mx600m \
         -cp $dir/NER/stanford-ner-2015-01-30/stanford-ner-3.5.1.jar \
         edu.stanford.nlp.ie.crf.CRFClassifier \
         -loadClassifier $dir/NER/stanford-ner-2015-01-30/classifiers/english.all.3class.distsim.crf.ser.gz \
         -textFile "$f" \
         -outputFormat inlineXML > "$g"
done

glob 模式$dir/NYTimesCorpus/*/*/*/*.xml 指定所需的 xml 文件恰好低于 NYTimesCorpus 3 级。那是错误的深度,然后更改模式中*/ 的数量。

如果 xml 文件可以出现在不同的深度,请使用 find,或在 bash 中使用:

shopt -s globstar nullglob
for f in $dir/NYTimesCorpus/**/*.xml; do

reference

【讨论】:

好的,首先让我说:好极了。绝对名列前茅。极好的。先生,向你致敬这个非凡的解决方案。然后跟进,在其他人没有的情况下,这个工作的机制是什么?这怎么可能改变以适应稍微不同的深度?

以上是关于bash 脚本导航目录子结构,然后对 .xml 文件进行操作的主要内容,如果未能解决你的问题,请参考以下文章

Bash 脚本检测我的 USB 何时插入,然后将其与目录同步

用于在分层目录结构中使用bash循环和AWK计算和提取结果的脚本

用于提取目录中所有 .tgz 的 Bash 脚本[重复]

终端打印

shell脚本的条件测试与比较

Bash 脚本在空行上打印“找不到命令”