3

I have a a.md file:

Start file

```
replace content here by a variable or result of a command such as pwd,
the whole content in this code block should be something like /Users/danny/MyProjects/CurrentDir
```
End file

And a script in update.sh to update file above:

#!/bin/sh

t=$(pwd)
echo $t
perl -i -p0e 's/(?<=```shell\n)[\s\S]*(?=\n```)/$t/s' a.md

It works fine with a string but I cannot replace with a variable such as $(pwd).

Danny
  • 883
  • 8
  • 33
  • "_It works fine with a string but I cannot replace with a variable such as $(pwd)_" -- I don't understand -- it works with `/.../$t/` but you want to have `/.../$(pwd)/` ? (why?) Or it works with a literal string but not with `$t`? – zdim Oct 06 '22 at 05:37
  • it add an empty line with `$t`. – Danny Oct 06 '22 at 06:27
  • "_it add an empty line with `$t`_" -- OK, thank you, as expected. (The Perl program there cannot see those shell variables, surprising as it may seem. We have to specifically pass them to the program.) I posted an answer, let me know if there are questions (I'll add more to it) – zdim Oct 06 '22 at 06:29

1 Answers1

2

A Perl command-line program in that shell script cannot use variables from the script just so but we need to pass variables to it somehow.

There are a few ways to do that, and perhaps using -s switch is simplest here

#!/bin/bash

t=$(pwd)
echo $t
perl -i -0777 -s -pe's/(?<=```shell\n)[\s\S]*(?=\n```)/$d/s' -- -d="$t" a.md

# or
# perl -i -0777 -s -pe'...' -- -d="$(pwd)" a.md

The -s for perl enables a basic support for switches for the program itself.

So that -d=... becomes available as $d in the program, either with the assigned value, here the value of the bash variable $t, or 1 if not assigned (-d). We can pass multiple variables this way, each in its own switch.

The -- after the program mark the start of arguments.

We do not need a shell variable but can directly use a command output, -var="$(pwd)".


Aside from using storage (files, databases, etc) or pipes, there are two more ways to directly pass arguments given to this command-line ("one-liner") program

  • Pass the variable as an argument and read it from @ARGV in the program

    t=$(pwd)
    perl -i -0777 -s -pe'BEGIN { $d = shift }; s/.../$d/s' "$t" a.md
    

    We need to also remove it from @ARGV so that the files can then be processed, which is what shift does, and need to do this in a BEGIN block since -p sets a loop.

  • Export a variable in bash making it an environment variable and a Perl script can then use that via %ENV variable

    export t=$(pwd)
    perl -i -0777 -s -pe's/.../$ENV{t}/s' a.md
    

    Note, it's t in the %ENV hash ($ENV{t}), the name of the variable, not $t (value)

See for example this post and this post

zdim
  • 64,580
  • 5
  • 52
  • 81
  • Yeah so we can assign the value by adding the flags like `-d="$(pwd)`. Appreciate it man! – Danny Oct 06 '22 at 06:36
  • @Danny Yes (and can do multiple ones, `-d="$(pwd)", -var="other" ...`). I added to the answer two other ways to do it, and a couple of links. – zdim Oct 06 '22 at 06:58