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)フォルダの実際のファイル名です。

答え1

ただし:

for f in *.html; do printf '%s\n' "[${f%.*}](./$f)"; done > index.md

ファイルが存在しない場合は、set -o nullglobzshyash)、またはshopt -s nullglobbash)を使用して*.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各入力行に対して1つのコマンドを実行しますが、行の各単語は別々の引数として渡されますが、各入力行に対して1つのコマンドを実行して完全な行に置き換え-I @@ます@@
  • {}内部使用パスワード議論shコマンド注入の脆弱性)
  • shvar${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
  • NULで区切られた出力を取得するには、ls次のように置き換えます。printf '%s\0' *
  • awk(GNU拡張)を使用したgrep -zNUL区切り出力の処理
  • xargs -r0-n(GNU拡張) //なしで-L-I生成するときに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"'

(ファイルが100,000以上の場合):

printf "%s\n" *.html | perl -pe 's/.html\n//;$_="[$_](./$_.html)\n"'

または(遅いが短い):

for f in *.html; do echo "[${f%.*}](./$f)"; done

関連情報