循环过滤查找并执行操作

时间:2016-11-12 02:53:55

标签: bash terminal pandoc

我有一堆Wordpress文件的垃圾转储,我正在尝试将它们全部转换为Markdown。

我写的脚本是:

htmlDocs=($(find . -print | grep -i '.*[.]html'))
for html in "${htmlDocs[@]}"
            do
                P_MD=${html}.markdown
                echo "${html} \> ${P_MD}"
                pandoc --ignore-args -r html -w markdown < "${html}" | awk 'NR > 130' | sed '/<div class="site-info">/,$d'  > "${P_MD}"                
            done

据我所知,第一行应该是在所有子目录中创建所有html文件的数组,然后for循环有一行来创建一个具有Markdown名称的变量(后跟调试回显),然后是实际的pandoc命令进行转换。

一次一个,这个命令有效。

然而,当我尝试执行它时,OSX给了我:

$ ./pandoc_convert.command 
./pandoc_convert.command: line 1: : No such file or directory
./pandoc_convert.command: line 1: : No such file or directory

O_0

帮助?

2 个答案:

答案 0 :(得分:2)

脚本失败的原因可能有很多,因为创建数组的方式不正确:

htmlDocs=($(find . -print | grep -i '.*[.]html'))

数组的格式为:NAME=(VALUE1 VALUE2 ... ),其中NAME是变量的名称,VALUE1VALUE2,其余是以字符分隔的字段存在于$IFS(输入字段分隔符)变量中。假设您找到带空格的文件名。然后表达式将在数组中创建单独的项目。

另一个问题是表达式不处理globbing,即基于*等特殊字符的shell扩展生成文件名:

mkdir dir.html
touch \ *.html
touch a\ b\ c.html

a=($(find . -print | grep -i '.*[.]html'))
for html in "${a[@]}"; do echo ">>>${html}<<<"; done

输出

>>>./a<<<
>>>b<<<
>>>c.html<<<
>>>./<<<
>>>a b c.html<<<
>>>dir.html<<<
>>> *.html<<<
>>>./dir.html<<<

我知道有两种方法可以解决此问题:1)暂时禁用通配,2)使用mapfile命令。

禁用全局

# Disable globbing, remember current -f flag value
[[ "$-" == *f* ]] || globbing_disabled=1
set -f

IFS=$'\n' a=($(find . -print | grep -i '.*[.]html'))
for html in "${a[@]}"; do echo ">>>${html}<<<"; done

# Restore globbing
test -n "$globbing_disabled" && set +f

输出

>>>./  .html<<<
>>>./a b c.html<<<
>>>./ *.html<<<
>>>./dir.html<<<

使用mapfile

在Bash 4中引入了mapfile。该命令将标准输入中的行读入索引数组:

mapfile -t a < <(find . -print | grep -i '.*[.]html')
for html in "${a[@]}"; do echo ">>>${html}<<<"; done

find选项

find命令选择所有类型的节点,包括目录。您应该使用-type选项,例如文件-type f

如果要使用正则表达式过滤结果集,请使用-regex选项,或使用-iregex进行不区分大小写的匹配:

mapfile -t a < <(find . -type f -iregex .*\.html$)
for html in "${a[@]}"; do echo ">>>${html}<<<"; done

输出

>>>./  .html<<<
>>>./a b c.html<<<
>>>./ *.html<<<

echoprintf

最后,don't use echo in new software。请改用printf

mapfile -t a < <(find . -type f -iregex .*\.html$)
for html in "${a[@]}"; do printf '>>>%s<<<\n' "$html"; done

替代方法

但是,我宁愿使用read

来管道循环
find . -type f -iregex .*\.html$ | while read line
do
  printf '>>>%s<<<\n' "$line"
done

在此示例中,read命令从标准输入中读取一行,并将值存储到line变量中。

虽然我喜欢mapfile功能,但我发现管道的代码更清晰。

答案 1 :(得分:1)

尝试添加bash shebang并设置IFS来处理文件夹和文件名中的空格:

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

htmlDocs=($(find . -print | grep -i '.*[.]html'))
for html in "${htmlDocs[@]}"
do
                P_MD=${html}.markdown
                echo "${html} \> ${P_MD}"
                pandoc --ignore-args -r html -w markdown < "${html}" | awk 'NR > 130' | sed '/<div class="site-info">/,$d'  > "${P_MD}" 
done
IFS=$SAVEIFS