Shell help text syntax for repeatable group of arguments - shell

I'm writing a help output for a Bash script. Currently it looks like this:
dl [m|r]… (<file>|<URL> [m|r|<index>]…)…
The meaning that I'm trying to convey (and elsewhere describe with words) is that (after a potential "m" and/or "r") there can be an endless list of sets of arguments. The first argument in each set is always a file or URL and the further arguments can each be "m", "r" or a number. After that, it starts over with a file or URL and so on.
In my special case, I could just write this:
dl [m|r]… (<file>|<URL>) (<file>|<URL>|m|r|<index>)…
This works, because listing a URL and then another URL with nothing in between is allowed, as well as listing an arbitrarily long chain of "m"s (it's just useless to do so) and pretty much any other combination.
But what if that wasn't the case? What if I had for example a command like this:
change (<from> <to>)…
…which would be used e.g. like this:
change from1 to1 from2 to2 from3 to3
Would the bracket syntax be correct here? I just guessed it based on the grouping of (a|b), but I wasn't able to find any documentation that uses this for multiple, non-exclusive arguments that belong together. Is there even a standard for this?

Related

Sort a property in HCL Block

I would like to move name property to the top of the block like this.
There are many resouce block in a file.
Before
resource "datadog_monitor" "A" {
enable_logs_sample = "true"
name = "name"
tags = ["env:dev"]
}
resource "datadog_monitor" "B" {
enable_logs_sample = "true"
name = "name"
tags = ["env:dev"]
}
After
resource "datadog_monitor" "A" {
name = "name"
enable_logs_sample = "true"
tags = ["env:dev"]
}
resource "datadog_monitor" "B" {
name = "name"
enable_logs_sample = "true"
tags = ["env:dev"]
}
OK, I think :help :global and the range/address mechanism is one of Vim's best and most underrated feature so it might deserve a detailed run down.
The core editing pattern is the same as in the commands I suggested in my previous answer to a similar question of yours:
on each line matching a specific regular expression pattern,
do something.
Note that it is a "pattern", not a one-off trick. You are not supposed to "learn" this answer by heart, or commit it to "muscle memory", or bookmark it for the next time you have the exact same problem. Instead, you are supposed to grok the logic behind it in a way that allows you to:
recognize a situation where it might come handy,
apply it without too much thinking.
So, in order to implement the editing pattern described above, we use the :global command, which works like this:
:[range]global/<pattern>/[range]<command>
where:
in range (optional, default is %),
mark each line matching <pattern>,
then execute <command> on range (optional, default is .).
Like lots of things in Vim, :global is conceptually cool but not necessarily useful on its own. The more familiar you are with ranges/addresses and the more Ex commands you know, the more useful it is.
In this specific case, ranges don't matter much but addresses and Ex commands do… and their sum makes problems like these solvable in, IMO, a pretty intuitive way.
Now, let's go back to our problem:
move every "name" line to the top of the block
and express it in terms that match our editing pattern:
mark every line matching name,
then move it below the closest line above matching resource.
Which is a simple:
:g/name/m?resource?
Of course, the exact regular expression patterns to use are context-dependent.
The trick is to internalize the patterns so that you already know how to use any new building block you might come upon.
There is really nothing even remotely god-like, here.

How to load value from dynamically specified parameter in NiFi

I have several processes with almost same flow like "Get some parameters, extract data from database according to them and upload them to target". The parameters vary slightly across processes as well as targets but only a bit. Most of the process is the same. I would like to extract those differences to parameter-context and dynamically load them. My idea is to have parameters defined following way and then using them.
So core of question is:
How to dynamically choose which parameter group load and use?
Having several parameter contexts with same-named/different-valued parameters and dynamically switching them would be probably the best, but it is not possible as far as I know.
Also duplicating flows is out-of-the-table. Any error correction would be spread out over several places and maintenance would be a nightmare.
Moreover, I know I can do it like "In GenetrateFlowFile for process A set value1=#{A_value1} and in GenetrateFlowFile for process B set value1=#{B_value1}. But this is tedious, error-prone and scales kinda bad. Not speaking of situation when I can have dozens of parameters and several processes. Also it is a kind of hardcoding, not configuring...
I was hoping for something like defining group=A and then using it like value1=#{ ${ group:append('_value1') } } but this does not work - it is evaluated as parameter literally named ${ group:append('_value1') }.
TL;DR: Use evaluateELString().
The actual solution is to set in GenetrateFlowFile processor group=A and in next UpdateAttribute processor set the following:
value1=${ group:prepend('hash{ '):append('_value1 }'):replace('hash', '#'):evaluateELString() }
The magic being done here is "Take value of group slap around it #{ and _value1 } to make it valid NiFi Expression Language statement and then evaluate it." (Notice - the word hash and function replace is there since I didn´t manage to escape the # char right before {.)
If you would like to have your value1 at the beginning of the statement then you can use following code. The result is same, it is easier to use (often-changed value value1 is at the beginning of the statement) and is less readable "what is really going on?"-wise.
value1=${ literal('value1'):prepend('_'):prepend(${ group }):prepend('hash{ '):append(' }'):replace('hash', '#'):evaluateELString() }

How to concatenate many files using their basenames?

I study genetic data from 288 fish samples (Fish_one, Fish_two ...)
I have four files per fish, each with a different suffix.
eg. for sample_name Fish_one:
file 1 = "Fish_one.1.fq.gz"
file 2 = "Fish_one.2.fq.gz"
file 3 = "Fish_one.rem.1.fq.gz"
file 4 = "Fish_one.rem.2.fq.gz"
I would like to apply the following concatenate instructions to all my samples, using maybe a text file containing a list of all the sample_name, that would be provided to a loop?
cp sample_name.1.fq.gz sample_name.fq.gz
cat sample_name.2.fq.gz >> sample_name.fq.gz
cat sample_name.rem.1.fq.gz >> sample_name.fq.gz
cat sample_name.rem.2.fq.gz >> sample_name.fq.gz
In the end, I would have only one file per sample, ideally in a different folder.
I would be very grateful to receive a bit of help on this one, even though I'm sure the answer is quite simple for a non-novice!
Many thanks,
Noé
I would like to apply the following concatenate instructions to all my
samples, using maybe a text file containing a list of all the
sample_name, that would be provided to a loop?
In the first place, the name of the cat command is mnemonic for "concatentate". It accepts multiple command-line arguments naming sources to concatenate together to the standard output, which is exactly what you want to do. It is poor form to use a cp and three cats where a single cat would do.
In the second place, although you certainly could use a file of name stems to drive the operation you describe, it's likely that you don't need to go to the trouble to create or maintain such a file. Globbing will probably do the job satisfactorily. As long as there aren't any name stems that need to be excluded, then, I'd probably go with something like this:
for f in *.rem.1.fq.gz; do
stem=${f%.rem.1.fq.gz}
cat "$stem".{1,2,rem.1,rem.2}.fq.gz > "${other_dir}/${stem}.fq.gz"
done
That recognizes the groups present in the current working directory by the members whose names end with .rem.1.fq.gz. It extracts the common name stem from that member's name, then concatenates the four members to the correspondingly-named output file in the directory identified by ${other_dir}. It relies on brace expansion to form the arguments to cat, so as to minimize code and (IMO) improve clarity.

Referencing Two-Word Variables in Applescript?

I'm attempting to get some data from an app called "Timing", which is local to my computer, and post it to a URL to notify a webhook, from which some process automation will occur.
According to the Applescript integration with Timing,
There is a time summary object that's returned from a command which I've successfully executed. When displayed as an alert, that data looks like this:
Can't get |times per project| of {id:5C6CD8C8-357F-4EE7-890C-5946DC03BBB9", overall total:1.18092493622303E+4, times per project:{Maintenance:81.091759443283, Youtube:4820.38001298904, |self improvement effors|:876.930474758148, Homework:2383.20326805115, |(no project)|:3647.64384698868}, overall total without tasks:1.18092493622303E+4, productivity score:0.388005592511, times per project without tasks:{Maintenance:81.091759443283, Youtube:4820.38001298904, |self improvement efforts|:876.930474758148, Homework:2383.20326805115, |(no project)|:3647.64384698868}, class:time summary}.
As you can see, (above), there is a property called productivity score, which is two words.
When attempting to get this datapoint from the object (which I will use to notify the webhook:)
set newnewVar to productivity score of newvar
display alert newvar
Obviously this wont work, because the variable name is two words. I've tried surrounding the name in quotes and surround it with other characters, but nothing seems to work, and the documentation for getting specific properties only has examples with variables with one word.
What's the solution to this problem?
In AppleScript, user-defined variables cannot generally have spaces. Typically they start with a letter or underscore, and then can contain only letters, numbers, or underscores. A user-defined variable can only contain spaces if it is contained within vertical pipes. So all of the following are valid variable forms: alphaUnit, slideRow3, _tempItem, |my variable|, left_hand_vector
However, any application or script that creates and uses a scripting definition can create commands and classes and properties that have multi-word names. For instance, if you look at the System Events app, you'll see that the Disk-Folder-File Suite has a class named disk item with properties like creation date. The reason this works is that these multi-word names are actually represented by a numeric (four-char) code: disk item is actually 'ditm' and creation date is 'ascd'. You often see these codes pop up in error strings like so:
"cannot make class ≪ditm≫ into..."
Make sure you have the scope right to invoke the dictionary — i.e. be within a tell block for the app or script that invokes the scripting dictionary — and the multi-word names should 'just work'. After compiling, you'll see them highlighted in a purple color that's just a bit different from the red of uncompiled text. You do not need to enclose dictionary terms in vertical pipes; if you do, they will be treated as user-defined variables and lose their special scripting purposes.

How can I check if a string is a valid file name for windows using R?

I've been writing a program in R that outputs randomization schemes for a research project I'm working on with a few other people this summer, and I'm done with the majority of it, except for one feature. Part of what I've been doing is making it really user friendly, so that the program will prompt the user for certain pieces of information, and therefore know what needs to be randomized. I have it set up to check every piece of user input to make sure it's a valid input, and give an error message/prompt the user again if it's not. The only thing I can't quite figure out is how to get it to check whether or not the file name for the .csv output is valid. Does anyone know if there is a way to get R to check if a string makes a valid windows file name? Thanks!
These characters aren't allowed: /\:*?"<>|. So warn the user if it contains any of those.
Some other names are also disallowed: COM, AUX, NUL, COM1 to COM9, LPT1 to LPT9.
You probably want to check that the filename is valid using a regular expression. See this other answer for a Java example that should take minimal tweaking to work in R.
https://stackoverflow.com/a/6804755/134830
You may also want to check the filename length (260 characters for maximum portability, though longer names are allowed on some systems).
Finally, in R, if you try to create a file in a directory that doesn't exist, it will still fail, so you need to split the name up into the filename and directory name (using basename and dirname) and try to create the directory first, if necessary.
That said, David Heffernan gives good advice in his comment to let Windows do the wok in deciding whether or not it can create the file: you don't want to erroneously tell the user that a filename is invalid.
You want something a little like this:
nice_file_create <- function(filename)
{
directory_name <- dirname(filename)
if(!file.exists(directory_name))
{
ok <- dir.create(directory_name)
if(!ok)
{
warning("The directory of that path could not be created.")
return(invisible())
}
}
tryCatch(
file.create(filename),
error = function(e)
{
warning("The file could not be created.")
}
)
}
But test it thoroughly first! There are all sorts of edge cases where things can fall over: try UNC network path names, "~", and paths with "." and ".." in them.
I'd suggest that the easiest way to make sure a filename is valid is to use fs::path_sanitize().
It removes control characters, reserved characters, and Windows-reserved filenames, truncating the string at 255 bytes in length.

Resources