Xargs 提取文件名

Xargs 提取文件名

我想找到.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(或在 中报告错误) 。与 一起,您还可以使用或 在zshhtmlzsh*.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 编码和%#HURI 编码,但我们仍然需要单独处理换行符。

或者与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
  • 替换lsprintf '%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

相关内容