How to combine a prefix to output of ls in bash?

Viewed 1667

Let's say I have some images in parent directory: ../imagea/a.png and ../images/b.png.

When I do:

ls ../images

# I get
../images/a.png
../images/b.png

How to add the prefix ![]( and the suffix ) for all these outputs?

I tried:

!ls ../images/*.png | cat

# am not sure what to do next

Required output

![](../images/a.png)
![](../images/b.png)

Help is appreciated.

4 Answers

Loop over the glob pattern, and print each line formatted as desired:

for filename in ../*.png; do echo '!'"[]($filename)"; done

The easiest solution is using the standard posix find command with printf action like this:

 find ../images -name "*.png" -printf '![](%p)\n'

Explanation:

../images - target directory

"*.png" - glob pattern

-printf - format action to output

'![](%p)\n' - format arguments to output full path name.

Example:

$ ls -l
total 8
drwxrwxr-x.  3 cfrm cfrm   15 Dec 13  2018 app
drwxrwxr-x.  2 cfrm cfrm   23 Mar 24  2019 app_5811_install
drwxrwxr-x. 13 cfrm cfrm 4096 Dec 12  2018 app_58_install
drwxrwxr-x.  2 cfrm cfrm 4096 Oct  3  2018 grants
-rwx------.  1 cfrm cfrm  526 Feb 17  2019 ic_start_all.sh
-rwx------.  1 cfrm cfrm  920 Oct  4  2018 ic_status_all.sh
-rwx------.  1 cfrm cfrm  984 Sep 27  2018 ic_stop_all.sh
-rwxrwxr-x.  1 cfrm cfrm 1693 Dec 13  2018 loadTrigger.sh



$ find . -name "*.sh" -printf '![](%p)\n'
![](./ic_stop_all.sh)
![](./ic_status_all.sh)
![](./loadTrigger.sh)
![](./ic_start_all.sh)

First, I disbelieve you. ls ../images would output only the basenames, like:

a.png
b.png
...etc...

A different command ls ../images/* could give the output you show.

Although on a system using the ls from GNU coreutils, like Linux, if the output is a terminal and the filenames are short like you showed, ls without options would do multicolumn output more like:

../images/aaaaa.png   ../images/ddddd.png  ../images/ggggg.png
../images/b.png       ../images/eeeee.png  ../images/hhhhhh.png
../images/ccccc.png   ../images/f.png      ../images/iiiiii.png

unless you have an alias (or shadowing function or script) that forces the -1 (one) option to prevent this. Or the actual names are (significantly) longer, as they probably should be. Or you are piping to something, even cat, because then the output of ls is the pipe not the terminal. These details matter.

For some cases sed is as good as awk, and usually terser:

ls | sed 's/^/![](/; s/$/)/'
# sed processes a string of command(s) for each line read from stdin, 
# and writes the result to stdout (by default, -n overrides this)
# s/old/new/ is string replacement using regex (which can be complex)
# ^ in old matches the beginning of the line
# $ in old matches the end of the line

# this assumes none of your filenames contains a newline character
# which Unix permits, but is rarely done because it is quite confusing

or since you like printf it can do the whole job:

printf '![](%s)\n' ../images/*
# printf takes a format string containing any mixture of literal text 
# (including backslash+letter escapes mostly the same as C et succ)
# and conversion specifiers beginning with % which each interpolate one argument
# it repeats the format as needed to handle all the arguments, so here 
# with one c.s. it repeats the format once for each argument = filename

# this 'works' even if a filename contains newline
# (but I don't think the result will work correctly as markdown)

Could you please try following.

awk 'BEGIN{for(i=1;i<ARGC;i++)print "![](..",ARGV[i]")"}' ../images/*.png

Output will be as follows(where a,b,c... .png are test files created by me for testing purposes).

![](.. ../images/a.png)
![](.. ../images/b.png)
![](.. ../images/c.png)
![](.. ../images/d.png)
Related