3

I am running a Docker Alpine based image which has bash installed.

bash --version
GNU bash, version 4.3.48(1)-release (x86_64-alpine-linux-musl)

In the following command, i am trying to convert first letter of month to lowercase but it's not working:

find ../ -type f -name "*.md" \
        -exec bash -c '
            f=${1#./}
            gzip -9 "$f"
            mv "$f".gz "$f"
            aws s3 cp "$f" s3://bucket_name/ --metadata time=$(date +%d-%b-%Y.%H%M | sed '\''s#\([A-Z]\)#\L\1#'\'') ' _ {} \;

The date attribute it assigns to the file(s) is:

"Metadata": {
    "timestamp": "10-LSep-2018.1054"
}

\L is not working in this case. The expected date should have been "10-sep-2018.1054"

How can i get it working with the bash version present in Docker image?

Technext
  • 7,887
  • 9
  • 48
  • 76
  • 1
    you claim \L is not working, but your example actually shows an unescaped L. to convert ONLY the first capital of any word to lowercase try `sed -E "s/\b[^A-Z]*[A-Z]/\L&/"` – Sam Sep 10 '18 at 11:18
  • @Sam: Extremely sorry for that typo. It's actually \L. – Technext Sep 10 '18 at 11:22
  • 1
    hm, it works for me, maybe you have a different version of sed? also, perhaps a simple `tr [:upper:] [:lower:]` would be enough for your purposes? – Sam Sep 10 '18 at 11:33
  • I just checked the version and it says "This is not GNU sed version 4.0". [This](https://unix.stackexchange.com/questions/16350/which-sed-version-is-not-gnu-sed-4-0) seems to be the case. Anyways, your first suggestion is not working and it may be because of the reason i just cited. I get this as output: `"L10-Sep-2018.1142"`. Second suggestions works though. – Technext Sep 10 '18 at 12:06
  • 2
    if it is of no concern that other capital letters need to be retained, i would go with `tr` for better readability. – Sam Sep 10 '18 at 12:34
  • @Sam: Kindly post your suggestion as answer. I will definitely wait for some time for a `sed` answer but if nothing comes up, i will accept yours. Though it is wide in its application but for my use-case, i feel it's safe to use it and readable too. – Technext Sep 10 '18 at 15:01

5 Answers5

3

As it turns out OP only has access to a minimal version of sed that does not recognize the \L replacement command and for his use case de-capitalizing ALL letters in the output is acceptable.

The most straightforward way to achieve this is with the command

tr [:upper:] [:lower:]
Sam
  • 811
  • 5
  • 9
1

The question could have been simplified by only showing the affected part:

date +%d-%b-%Y.%H%M | sed '\''s#\([A-Z]\)#L\1#'\''

In first place let me "clean" it:

date +%d-%b-%Y.%H%M | sed 's#\([A-Z]\)#L\1#'

What I see here is that you are using L as a literal letter, not as the command. You need to escape it (\L) like this:

date +%d-%b-%Y.%H%M | sed 's#\([A-Z]\)#\L\1#'

You can test it executing:

:~# docker container run --rm alpine /bin/sh
/ # date +%d-%b-%Y.%H%M | sed 's#\([A-Z]\)#\L\1#'
10-LSep-2018.1510
  • Thanks for the response but i did not try simplifying because the original version (whole command) that i posted is what i am using. Tried your suggestion but it throws error: `-c: line 4: unexpected EOF while looking for matching `)'` – Technext Sep 10 '18 at 12:16
  • Yes, because my version is not using the needed escaping ('\''something'\''). It seems that your problem is the sed version included in your alpine, that doesn't have this \L command. Have you tried the docker command I gave you to confirm that the sed you are using is the problem? Because I am using alpine:latest (11cd0b38bc3c 2 months ago 4.41MB) and sed is working fine for me. – binary-sequence Sep 10 '18 at 12:39
  • If i run your Docker command, it prints the date in correct format. However, if i run the same `Alpine` container with this command, `docker container run --rm alpine sed --version`, i get `This is not GNU sed version 4.0` as output. This is exactly what i get when i print output of `sed --version` in my script. Going with the `sed` version details of yours and mine, i _assume_ `\L` _might_ be supported in my image as well but needs some tweaking in the way i am using it. – Technext Sep 10 '18 at 12:51
  • So i just confirmed that my `sed` version _also_ supports `\L`. I just used my container in place of yours in the command you suggested and it's printing the date properly. So as i said earlier, some tweaking is required in the original command i posted. – Technext Sep 10 '18 at 13:09
  • I think it is related to the escaping level. Bash escaping (\L) may be working before sed escaping (which will get only L). Can you try double escaping \\L? Like: sed 's#\([A-Z]\)#\\L\1#' – binary-sequence Sep 10 '18 at 14:12
  • I have tried that already but the output was the same i.e., `10-LSep-2018.1054` – Technext Sep 10 '18 at 14:40
  • 1
    ah, sorry, my bad. The docker command I sent is wrong. The pipe command is not executed inside the container, but outside. Only the date command is executed inside the container, then the output is sent to the host, and the host executed the sed command over it. I have verified that the sed command inside alpine image doesn't have the \L command. – binary-sequence Sep 10 '18 at 15:08
  • Ok. That's a nice observation :) Thanks for letting me know. – Technext Sep 10 '18 at 15:44
1

This GNU sed should do:

$ date +'%d-%b-%Y.%H%M' | sed 's/-./\L&/'
10-sep-2018.1332

To escape it properly in bash -c '...':

bash -c '... time="$(date +"%d-%b-%Y.%H%M" | sed "s/-./\L&/")" ...'

If you don't have GNU sed available (it is needed for the \L extension), just save the date to a variable and use parameter expansion:

$ d=$(date +'%d-%b-%Y.%H%M')
$ echo "${d,,}"
10-sep-2018.1337
PesaThe
  • 7,259
  • 1
  • 19
  • 43
  • Thanks for letting me know that `GNU sed` supports `\L`. +1 for that. I have seen the second variant but i want to avoid handling the date separately. I might go with the `tr` that @Sam suggested if i don't get a `sed` answer. – Technext Sep 10 '18 at 12:11
  • Using your latest suggestion, i get the dir name as `10L-Sep-2018.1540` – Technext Sep 10 '18 at 15:43
1

This might work for you (GNU sed):

sed 's/$/:JjFfMmAaSsOoNnDd/;s/\([JFMASOND]\)\(.*\):.*\1\(.\).*/\3\2/' file

This replaces an upper-case letter J,F,M,A,S,O,N or D with its lower-case complement.

potong
  • 55,640
  • 6
  • 51
  • 83
0

There are few variants of a possible answer in this other thread, but the one that seems to satisfy your needs, and it's also the easiest to read, is the following one:

sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'

That should work pretty much everywhere, including macOS.

Andrea Giammarchi
  • 3,038
  • 15
  • 25