Shell – script to use the output of a command (ls) and use it in another command

io-redirectionshell

I have a collection of pdf files I would like to convert to epub. I know Calibre's command ebook-convert will do the trick (nicely might I add). However
I have more than one file.

I'd like to be able to run a script that runs ls > file then something runs through said file and parses it so each entry is a variable. Then uses the variables to as the input file for ebook-convert; and somehow have the variable as the output file but append a .epub to the end of the file name?

Best Answer

I'll expand on jasonwryan's answer, which explains the what but not the how or the why.

You can use the output of a command as arguments to another command. This is called command substitution.

some_text='Hello, world'
uppercased="$(echo "$some_text" | tr a-z A-Z)"
echo "Now, it's $uppercased"

However, $(ls …) is horrible for two reasons:

  • Do not parse the output of ls. It's not designed to be parsable.
  • "$(some-command)" gives you a string, which is the output of that command. If you have a command that returns a list of elements, you need to parse that string into individual elements. That's fiddly and unreliable unless you can find a simple separator. For file names, you can't easily find a separator, because file names on most unices can contain every character⁰.

Note that if you write $(some-command) rather than "$(some-command)", the output of the command is split into words and undergoes globbing. Until you understand the previous sentence, always put double quotes around command substitutions. When you do understand, always put double quotes unless you know why you can't put them.

Fortunately, generating the list of files that match a certain pattern is a feature that's built into the shell. It's called globbing.

echo *.pdf

To act on multiple files, you use a loop.

for x in *.pdf; do …; done

The remaining hurdle is to generate the name of the target file. The shell has some simple text manipulation commands, amongst which ${foo%SUFFIX} to get the value of a variable with a suffix removed. (There's also ${foo#PREFIX}.)

for x in *.pdf; do
  ebook-convert "$x" "${x%.pdf}.epub"
done

Note the double quotes around variable substitutions. The reason is the same as for command substitutions.

Except a null character, but most shells can't cope with these.