我想找到.html
一个文件夹中的所有文件并附加[file](./file.html)
另一个名为index.md
.我尝试了以下命令:
ls | awk "/\.html$/" | xargs -0 -I @@ -L 1 sh -c 'echo "[${@@%.*}](./@@)" >> index.md'
但它不能@@
在命令内部替换?我究竟做错了什么?
注意:文件名可以包含空格等有效字符
澄清:
index.md
每行的[file](./file.html)
file 是文件夹中的实际文件名
答案1
做就是了:
for f in *.html; do printf '%s\n' "[${f%.*}](./$f)"; done > index.md
当没有文件时,使用set -o nullglob
( zsh
, yash
) 或shopt -s nullglob
( bash
) 来*.html
展开为空*.html
(或在 中报告错误) 。与 一起,您还可以使用或 在zsh
html
zsh
*.html(N)
ksh93
~(N)*.html
。
或者通过一次printf
调用zsh
:
files=(*.html)
rootnames=(${files:r})
printf '[%s](./%s)\n' ${basenames:^files} > index.md
请注意,根据您使用的 Markdown 语法,您可能需要对标题如果文件名包含一些有问题的字符,则对 URI 部分进行 URI 编码。如果不这样做,甚至最终可能会引入某种形式的 XSS 漏洞(具体取决于上下文)。使用 ksh93,您可以执行以下操作:
for f in *.html; do
title=${ printf %H "${file%.*}"; }
title=${title//$'\n'/"<br/>"}
uri=${ printf '%#H' "$file"; }
uri=${uri//$'\n'/%0A}
printf '%s\n' "[$title]($uri)"
done > index.md
其中%H
¹ 执行 HTML 编码和%#H
URI 编码,但我们仍然需要单独处理换行符。
或者与perl
:
perl -MURI::Encode=uri_encode -MHTML::Entities -CLSA -le '
for (<*.html>) {
$uri = uri_encode("./$_");
s/\.html\z//;
$_ = encode_entities $_;
s:\n:<br/>:g;
print "[$_]($uri)"
}'
用于<br/>
换行符。您可能想使用  来代替,或者更一般地决定为不可打印字符选择某种形式的替代表示形式。
您的代码中有一些错误:
- 解析输出
ls
- 在双引号内使用
$
原义的a - 用于可以做
awk
的事情grep
(本身并没有错,但太过分了) xargs -0
当输入不是 NUL 分隔时使用-I
与 冲突-L 1
。-L 1
是为每行输入运行一个命令,但该行中的每个单词作为单独的参数传递,而-I @@
为每一行输入运行一个命令,并使用整行(减去尾随空格,并且仍在处理引用)来替换@@
。- 使用
{}
内部代码的论证sh
(命令注入漏洞) - 在
sh
,var
在${var%.*}
是一个变量名,它不适用于任意文本。 - 用于
echo
任意数据。
如果你想使用xargs -0
,你需要类似的东西:
printf '%s\0' * | grep -z '\.html$' | xargs -r0 sh -c '
for file do
printf "%s\n" "[${file%.*}](./$file)"
done' sh > file.md
- 替换
ls
为printf '%s\0' *
以获得 NUL 分隔的输出 awk
使用grep -z
(GNU 扩展)来处理 NUL 分隔的输出xargs -r0
(GNU 扩展)没有任何-n
//-L
,-I
因为当我们生成 a 时sh
,我们不妨让它处理尽可能多的文件- 已经
xargs
通过的话作为额外的的参数sh
(成为位置参数在内联代码内),而不是在代码参数内。 - 这意味着我们可以更轻松地将它们存储在变量中(这里
for file do
默认情况下循环位置参数),因此我们可以使用${param%pattern}
参数扩展运算符。 - 使用
printf
而不是echo
.
不用说,使用它而不是像上面的示例那样for
直接在文件上进行循环是没有意义的。*.html
1 不过,在我的 ksh93 版本中,它似乎无法正确处理多字节字符(GNU 系统上的 ksh93u+)
答案2
不解析 ls。
你不需要xargs
这个,你可以使用find -exec
.
尝试这个,
find . -maxdepth 1 -type f -name "*.html" -exec \
sh -c 'f=$(basename "$1"); echo "[${f%.*}]($1)" >> index.md' sh {} \;
如果你想要使用xargs
,请使用这个非常相似的版本:
find . -maxdepth 1 -type f -name "*.html" -print0 | \
xargs -0 -I{} sh -c 'f=$(basename "$1"); echo "[${f%.*}]($1)" >> index.md' sh {} \;
另一种无需运行xargs
或的方法-exec
:
find . -maxdepth 1 -type f -name "*.html" -printf '[%f](./%f)\n' \
| sed 's/\.html\]/]/' \
> index.md
答案3
你真的需要吗xargs
?
ls *.html | perl -pe 's/.html\n//;$_="[$_](./$_.html)\n"'
(如果您有超过100000个文件):
printf "%s\n" *.html | perl -pe 's/.html\n//;$_="[$_](./$_.html)\n"'
或(较慢,但较短):
for f in *.html; do echo "[${f%.*}](./$f)"; done