循环筛选查找并执行操作
Looping over filtered find and performing an operation
我有一堆 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 名称的变量(后跟一个debugging echo),然后实际的 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
帮忙?
尝试添加 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
脚本失败的原因可能有很多,因为你创建数组的方式不正确:
htmlDocs=($(find . -print | grep -i '.*[.]html'))
数组赋值形式为:NAME=(VALUE1 VALUE2 ... )
,其中NAME
为变量名,VALUE1
、VALUE2
,其余为字段分隔$IFS
(输入字段分隔符)变量中存在的字符。假设您找到一个带空格的文件名。然后表达式将在数组中创建单独的项目。
另一个问题是表达式不处理通配符,即基于 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) 暂时禁用 globbing,以及 2) 使用 mapfile
命令。
禁用 Globbing
# 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中引入了mapfile
4. 该命令从标准输入中读取行到一个索引数组中:
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<<<
echo
对比 printf
最后,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
功能,但我发现带有管道的代码更清晰。
我有一堆 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 名称的变量(后跟一个debugging echo),然后实际的 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
帮忙?
尝试添加 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
脚本失败的原因可能有很多,因为你创建数组的方式不正确:
htmlDocs=($(find . -print | grep -i '.*[.]html'))
数组赋值形式为:NAME=(VALUE1 VALUE2 ... )
,其中NAME
为变量名,VALUE1
、VALUE2
,其余为字段分隔$IFS
(输入字段分隔符)变量中存在的字符。假设您找到一个带空格的文件名。然后表达式将在数组中创建单独的项目。
另一个问题是表达式不处理通配符,即基于 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) 暂时禁用 globbing,以及 2) 使用 mapfile
命令。
禁用 Globbing
# 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中引入了mapfile
4. 该命令从标准输入中读取行到一个索引数组中:
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<<<
echo
对比 printf
最后,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
功能,但我发现带有管道的代码更清晰。