I would like to find all the .html
files in a folder and append [file](./file.html)
to another file called index.md
. I tried the following command:
ls | awk "/\.html$/" | xargs -0 -I @@ -L 1 sh -c 'echo "[${@@%.*}](./@@)" >> index.md'
But it can't substitute @@
inside the command? What am I doing wrong?
Note: Filename can contain valid characters like space
Clarification:
index.md
would have each line with [file](./file.html)
where file is the actual file name in the folder
Best Answer
Just do:
Use
set -o nullglob
(zsh
,yash
) orshopt -s nullglob
(bash
) for*.html
to expand to nothing instead of*.html
(or report an error inzsh
) when there's nohtml
file. Withzsh
, you can also use*.html(N)
or inksh93
~(N)*.html
.Or with one
printf
call withzsh
:Note that, depending on which markdown syntax you're using, you may have to HTML-encode the title part and URI-encode the URI part if the file names contain some problematic characters. Not doing so could even end up introducing a form of XSS vulnerability depending on context. With ksh93, you can do it with:
Where
%H
¹ does the HTML encoding and%#H
the URI encoding, but we still need to address newline characters separately.Or with
perl
:Using
<br/>
for newline characters. You may want to use  instead or more generally decide on some form of alternative representation for non-printable characters.There are a few things wrong in your code:
ls
$
meant to be literal inside double quotesawk
for something thatgrep
can do (not wrong per se, but overkill)xargs -0
when the input is not NUL-delimited-I
conflicts with-L 1
.-L 1
is to run one command per line of input but with each word in the line passed as separate arguments, while-I @@
runs one command for each line of input with the full line (minus the trailing blanks, and quoting still processed) used to replace@@
.{}
inside the code argument ofsh
(command injection vulnerability)sh
, thevar
in${var%.*}
is a variable name, it won't work with arbitrary text.echo
for arbitrary data.If you wanted to use
xargs -0
, you'd need something like:ls
withprintf '%s\0' *
to get a NUL-delimited outputawk
withgrep -z
(GNU extension) to process that NUL-delimited outputxargs -r0
(GNU extensions) without any-n
/-L
/-I
, because while we're at spawning ash
, we might as well have it process as many files as possiblexargs
pass the words as extra arguments tosh
(which become the positional parameters inside the inline code), not inside the code argument.for file do
which loops over the positional parameters by default) so we can use the${param%pattern}
parameter expansion operator.printf
instead ofecho
.It goes without saying that it makes little sense to use that instead of doing that
for
loop directly over the*.html
files like in the top example.¹ It doesn't seem to work properly for multibyte characters in my version of ksh93 though (ksh93u+ on a GNU system)