# How to create a UUID inside CWL?

**URL:** <https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303>\
**Category:** CWL Questions\
**Created:** [February 10, 2021, 7:50pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303 "2021-02-10T19:50:15Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![steve](https://avatars.discourse-cdn.com/v4/letter/s/f19dbf/32.png) [@steve](https://cwl.discourse.group/u/steve)\
**Post date:** [February 10, 2021, 7:50pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/1 "2021-02-10T19:50:15Z")

</div>

Due to the issue described [here](https://github.com/common-workflow-language/cwltool/issues/1403) where input files with the same `basename` cause errors with a directory `InitialWorkDirRequirement`, I need to find a way to generate unique filenames that will not conflict with each other.

Ideally, I would just use a Javascript expression inside my CWL to accomplish this, but I could not get any [of these suggested methods to generate random strings](https://stackoverflow.com/questions/1349404/generate-random-string-characters-in-javascript) to work (or they required huge amounts of custom code too large to easily use across many CWL’s).

I did come up with one solution that uses Python’s `uuid` library;

```
requirements:
  InitialWorkDirRequirement:
    listing:
      - entryname: run.sh
        entry: |-
          set -euo pipefail
          output_file=\$(python3 -c "import uuid; print('_maf2bed_merged.' + str(uuid.uuid4()) + '.bed')")
          grep -v '#' "$1" | grep -v 'Hugo' | cut -f5-7 | sort -V -k1,1 -k2,2n > "\$output_file"

outputs:
  output_file:
    type: File
    outputBinding:
      glob: _maf2bed_merged.*.bed

```

This works, but has limitations / annoyances in that it messes up the input bindings for the other CLI args I might want to use, and it relies on having Python available which might not be the case.

Is there a way to do something like this directly within CWL?

At the very least, I would like to avoid needing to use the `InitialWorkDirRequirement`, and I was hoping there was a method where I could use a shell expression, like this;

```
output_filename:
    valueFrom: ${
       python -c "import uuid; print( 'file.' + str(uuid.uuid4()) + '.txt' )"
    }

```

But I could not find a way to implement that either.

---

<div class="post-metadata">

**Author:** ![tetron](https://yyz2.discourse-cdn.com/free1/user_avatar/cwl.discourse.group/tetron/32/40_2.png) [@tetron](https://cwl.discourse.group/u/tetron)\
**Post date:** [February 10, 2021, 8:31pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/2 "2021-02-10T20:31:18Z")

</div>

Backing up a step, each input file will have a unique path (just not a unique name), what’s the reason you want to put them all into the working directory and not refer to them as regular input files?

---

<div class="post-metadata">

**Author:** ![steve](https://avatars.discourse-cdn.com/v4/letter/s/f19dbf/32.png) [@steve](https://cwl.discourse.group/u/steve)\
**Post date:** [February 10, 2021, 9:21pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/3 "2021-02-10T21:21:54Z")

</div>

Because that breaks Singularity; [Singularity exec stops working when command line args are too long · Issue #5815 · hpcng/singularity · GitHub](https://github.com/hpcng/singularity/issues/5815)

---

<div class="post-metadata">

**Author:** ![steve](https://avatars.discourse-cdn.com/v4/letter/s/f19dbf/32.png) [@steve](https://cwl.discourse.group/u/steve)\
**Post date:** [February 10, 2021, 9:32pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/4 "2021-02-10T21:32:07Z")

</div>

something I had considered was instead of copying the files into the staging dir like this;

```auto
  InitialWorkDirRequirement:
    listing:
      - entryname: some_dir # <- put all the input files into a dir
        writable: true
        entry: "$({class: 'Directory', listing: inputs.input_files})"

```

was to instead copy the files’ entire directory tree into the dir, which would include the unique filepath component that would avoid name conflicts. However, I couldnt figure out how to accomplish that.

---

<div class="post-metadata">

**Author:** ![tetron](https://yyz2.discourse-cdn.com/free1/user_avatar/cwl.discourse.group/tetron/32/40_2.png) [@tetron](https://cwl.discourse.group/u/tetron)\
**Post date:** [February 10, 2021, 9:41pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/5 "2021-02-10T21:41:59Z")

</div>

Ok, some runners like Toil do have issues with large numbers of input files. The Toil developers were working on a fix, I just nudged them about it.

If you have an array of files, you could rename them sequentially like this:

```auto
cwlVersion: v1.0
class: ExpressionTool
requirements:
  InlineJavascriptRequirement: {}
inputs:
  fn: File[]
outputs:
  renamed: File[]
expression: |-
  ${
  for (var i = 0; i < inputs.fn.length; i++) {
   inputs.fn[i].basename = i + "_" + inputs.fn[i].basename;
  }
  return {renamed: inputs.fn};
  }

```

By changing the “basename” you change the name the file will be staged to.

---

<div class="post-metadata">

**Author:** ![steve](https://avatars.discourse-cdn.com/v4/letter/s/f19dbf/32.png) [@steve](https://cwl.discourse.group/u/steve)\
**Post date:** [February 10, 2021, 9:59pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/6 "2021-02-10T21:59:16Z")

</div>

Thanks, this looks helpful. But how do I use this within a `CommandLineTool`? For example, one like this;

```auto
#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: ["ls", "-la", "some_dir"]
doc: "CWL to save a listing of the execution Directory for debugging"

requirements:
  InlineJavascriptRequirement: {}

  InitialWorkDirRequirement:
    listing:
      - entryname: some_dir
        writable: true
        entry: "$({class: 'Directory', listing: inputs.input_files})"

stdout: ls.txt

inputs:
  input_files:
    type: File[]

outputs:
  output_file:
    type: stdout

```

---

<div class="post-metadata">

**Author:** ![tetron](https://yyz2.discourse-cdn.com/free1/user_avatar/cwl.discourse.group/tetron/32/40_2.png) [@tetron](https://cwl.discourse.group/u/tetron)\
**Post date:** [February 10, 2021, 10:09pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/7 "2021-02-10T22:09:59Z")

</div>

Try this

```auto
  InitialWorkDirRequirement:
    listing:
      - entryname: some_dir
        writable: true
        entry: |-
            ${
              for (var i = 0; i < inputs.fn.length; i++) {
                inputs.input_files[i].basename = i + "_" + inputs.input_files[i].basename;
              }
              return {class: 'Directory', listing: inputs.input_files};
            }

```

---

<div class="post-metadata">

**Author:** ![steve](https://avatars.discourse-cdn.com/v4/letter/s/f19dbf/32.png) [@steve](https://cwl.discourse.group/u/steve)\
**Post date:** [February 10, 2021, 10:25pm UTC](https://cwl.discourse.group/t/how-to-create-a-uuid-inside-cwl/303/8 "2021-02-10T22:25:58Z")

</div>

cool that works. I had to fix one typo;

```
  InitialWorkDirRequirement:
    listing:
      - entryname: some_dir
        writable: true
        entry: |-
            ${
              for (var i = 0; i < inputs.input_files.length; i++) {
                inputs.input_files[i].basename = inputs.input_files[i].basename + "." + i;
              }
              return {class: 'Directory', listing: inputs.input_files};
            }

```

thanks so much
