Converting a draft script from bash to Make - makefile

I like to have a script which will fill in front matter when I write new blog posts. In the past, I did this using Bash as seen below.
#!/bin/bash
# Set some variables
export site_path=~/Documents/Blog
drafts_path=~/Documents/Blog/_drafts
title="$1"
# Create the filename
title=$(awk '{print tolower($0)}' <<<"$title")
filename="$title.markdown"
file_path="$drafts_path/$filename"
echo "File path: $file_path"
# Create the file, Add metadata fields
cat >"$file_path" <<EOL
---
title: "$title"
layout: post
tags:
---
EOL
# Open the file in BBEdit
bbedit "$file_path"
exit 0
While not the nicest code, it does the job. As I've moved my other scripts to using Make, I'd like to do the same here. Here the section of my Makefile where I've defined the draft rule. I think I've escaped all variables, but it still will not run. Can someone explain where I may be going wrong?
SITE_PATH=~/Documents/Blog \
DRAFTS_PATH=~/Documents/Blog/_drafts \
TITLE="$$1" \
TITLE="$$(awk '{print tolower($$0)}' <<<"$$TITLE")" \
FILENAME="$$TITLE.markdown" \
FILE_PATH="${DRAFTS_PATH}/$$FILENAME" \
FILE_PATH="$${FILE_PATH}" \
cat >"$${FILE_PATH}" <<EOL \
--- \
title: "$$title" \
layout: post \
tags: \
--- \
EOL \
# Open the file in BBEdit
bbedit "$${FILE_PATH}" \
exit 0
Update: For reference, the complete Makefile is here where draft simply executes the original shell script.

Related

How to execute bash variable with double quotes and get the output in realtime

I have a variable that has a command that I want to run.
It has a bunch of double-quotes. when I echo it, it looks beautiful.
I can copy-paste it and run it just fine.
I tried simply $cmd, but it doesn't work. I get an error as if the command is malformed.
I then tried running it via eval "$cmd" or similarly, bash -c "$cmd", which works, but I don't get any output until the command is done running.
Example with bash -c "$cmd":
This runs the command, BUT I don't get any output until the command is done running, which sucks and I'm trying to fix that:
cmd="docker run -v \"$PROJECT_DIR\":\"$PROJECT_DIR\" \
-v \"$PPI_ROOT_DIR/utilities/build_deploy/terraform/modules/\":/ppi_modules \
--workdir \"$PROJECT_DIR/terraform\" \
--env TF_VAR_aws_account_id=$AWS_ACCOUNT_ID \
--env TF_VAR_environment=${ENVIRONMENT} \
--env TF_VAR_region=${AWS_DEFAULT_REGION:-us-west-2} \
${OPTIONAL_AWS_ENV_VARS} \
${CUSTOM_TF_VARS} \
${TERRAFORM_BASE_IMAGE} \
init --plugin-dir=/.terraform/providers \
-reconfigure \
-backend-config=\"bucket=${AWS_ACCOUNT_ID}-tf-remote-state\" \
-backend-config=\"key=${ENVIRONMENT}/${PROJECT_NAME}\" \
-backend-config=\"region=us-west-2\" \
-backend-config=\"dynamodb_table=terraform-locks\" \
-backend=true"
# command output looks good. I can copy and paste it and run it my terminal too.
echo $cmd
# Running the command via bash works,
# but I don't get the output until the command is done running,
# which is what I'm trying to fix:
bash -c "$cmd"
Here is an example using bash array.
It prints it to screen perfectly, but just like running it like $cmd, it throws an error as if the command is malformed:
cmd=(docker run -v \"$PROJECT_DIR\":\"$PROJECT_DIR\" \
-v \"$PPI_ROOT_DIR/utilities/build_deploy/terraform/modules/\":/ppi_modules \
--workdir \"$PROJECT_DIR/terraform\" \
--env TF_VAR_aws_account_id=$AWS_ACCOUNT_ID \
--env TF_VAR_environment=${ENVIRONMENT} \
--env TF_VAR_region=${AWS_DEFAULT_REGION:-us-west-2} \
${OPTIONAL_AWS_ENV_VARS} \
${CUSTOM_TF_VARS} \
${TERRAFORM_BASE_IMAGE} \
init --plugin-dir=/.terraform/providers \
-reconfigure \
-backend-config=\"bucket=${AWS_ACCOUNT_ID}-tf-remote-state\" \
-backend-config=\"key=${ENVIRONMENT}/${PROJECT_NAME}\" \
-backend-config=\"region=us-west-2\" \
-backend-config=\"dynamodb_table=terraform-locks\" \
-backend=true)
echo "${cmd[#]}"
"${cmd[#]}"
How can I execute a bash variable that has double-quotes, but run it so I get the output in realtime, just as if I executed via $cmd (which doesn't work)
Similar to these questions, but my question is to run it AND get the output in realtime:
Execute command containing quotes from shell variable
Bash inserting quotes into string before execution
bash script execute command with double quotes, single quotes and spaces
In your array version, double quotes escaped by a backslash become part of the arguments, which is not intended.
So removing backslashes should fix the issue.

Bash/WSL2: Is it possible to send files into the Windows directory from Linux?

#!/bin/bash
youtube-dl \
--ignore-errors \
--no-playlist \
--prefer-free-formats \
--no-call-home \
--extract-audio \
$1 \
--output 'C:\Users\Daniel\Music\Other\$2.%(ext)s'
Right now this script just puts the downloaded file into PWD, with that entire string as it's name. My question is:
Is it possible to use a Windows folder as a destination, or is this a limitation of WSL?
Help is appreciated.
in the wsl the default mount point for C: is /mnt/c/
so change the last line to:
"/mnt/c/Users/Daniel/Music/Other/$2.%(ext)s"
double quotes (see comment from #CharlesDuffy)

GNU parallel read from several files

I am trying to use GNU parallel to convert individual files with a bioinformatic tool called vcf2maf.
My command looks something like this:
${parallel} --link "perl ${vcf2maf} --input-vcf ${1} \
--output-maf ${maf_dir}/${2}.maf \
--tumor-id ${3} \
--tmp-dir ${vcf_dir} \
--vep-path ${vep_script} \
--vep-data ${vep_data} \
--ref-fasta ${fasta} \
--filter-vcf ${filter_vcf}" :::: ${VCF_files} ${results} ${tumor_ids}
VCF_files, results and tumor_ids contain one entry per line and correspond to one another.
When I try and run the command I get the following error for every file:
ERROR: Both input-vcf and output-maf must be defined!
This confused me, because if I run the command manually, the program works as intended, so I dont think that the input/outpit paths are wrong. To confirm this, I also ran
${parallel} --link "cat ${1}" :::: ${VCF_files} ${results} ${tumor_ids},
which correctly prints the contents of the VCF files, whose path is listed in VCF_files.
I am really confused what I did wrong, if anyone could help me out, I'd be very thankful!
Thanks!
For a command this long I would normally define a function:
doit() {
...
}
export -f doit
Then test this on a single input.
When it works:
parallel --link doit :::: ${VCF_files} ${results} ${tumor_ids}
But if you want to use a single command it will look something like:
${parallel} --link "perl ${vcf2maf} --input-vcf {1} \
--output-maf ${maf_dir}/{2}.maf \
--tumor-id {3} \
--tmp-dir ${vcf_dir} \
--vep-path ${vep_script} \
--vep-data ${vep_data} \
--ref-fasta ${fasta} \
--filter-vcf ${filter_vcf}" :::: ${VCF_files} ${results} ${tumor_ids}
GNU Parallel's replacement strings are {1}, {2}, and {3} - not ${1}, ${2}, and ${3}.
--dryrun is your friend when GNU Parallel does not do what you expect it to do.

How to get Makefile to only produce a file name without extension?

I'm trying to make a Makefile that exports a markdown file to a pdf file that uses the same filename as the original markdown file. I used "basename" command but it produces "inputfile.md.pdf" instead of "inputfile.pdf".
Please see my code below (I adapted a code I found on the Internet. Thank you!):
.PHONY: pdf docx apa format
FILES := $(wildcard ./*.md)
pdf:
for file in $(FILES); do \
pandoc $$file \
--bibliography mypath \
--csl mypath \
--filter pandoc-citeproc \
--template eisvogel \
-o $(basename $$file).pdf; \
open $(basename $$file).pdf; \
done
Anyone who can help me? I'm a novice in Makefile (and programming in general) so any detailed help would be very much appreciated.
I also tried these codes below, but they generated an error message:
-o $(basename -s ".md" $$file).pdf; \
-o $(basename -s .md $$file).pdf; \
The way you write $(basename …) you get the basename make function. This would normally the right thing, but you try to reference a shell variable file in its argument, which is unavailable at the make layer.
In this case, it is probably easiest to call the basename shell utility, at the shell level. Therefore, you need to escape the $ to get shell substitution, like this:
-o "$$(basename -s .md $$file)".pdf; \
open "$$(basename -s .md $$file)".pdf; \
Alternatively, you could try to move the loop to the make layer, perhaps using foreach.

BASH WHILE loop not hitting CASE switch

Hey guys title pretty much says it, but I'm echoing two variables into a BASH loop to kick it off, and (supposedly) using a case to be able to identify where they are and run a similar but separate (missing -k flag on second go around) wget statement. I hit my git checkout but it doesn't seem like I'm entering my cases. How do I fix this, or is there a better way to do it since I'm just dropping a -k flag?
#!/bin/bash
echo -e "render\nstorage" | while read x; do
git checkout "$x"
case $x in
$1)
wget "${WGDOMAIN}" -r -l INF -k -p \
--no-check-certificate \
--strict-comments \
--warc-header="Operator: Web Archiver" \
--warc-file="$WGDOMAIN" \
--warc-dedup="${WGDOMAIN}.cdx" \
--warc-cdx=on 2> session.log
;;
$2)
wget "${WGDOMAIN}" -r -l INF -p \
--no-check-certificate \
--strict-comments \
--warc-header="Operator: Web Archiver" \
--warc-file="$WGDOMAIN" \
--warc-dedup="${WGDOMAIN}.cdx" \
--warc-cdx=on 2> session.log
;;
$1|$2)
git add . && git ci -m"Archived: ${DATE}"
git push origin "$x"
;;
esac
done
Called with no positional parameters your script will not do anything inside the case statement as $1 and $2 are empty. Besides that, the last case option $1|$2 will never be reached as the prior ones will match. May be you should get that commands out of the case.

Resources