How to understand usage information of linux commands? - command-line-arguments

Example: what does it mean, '[]' and '[[]]' options ?
usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]
[-l limit] [-o ssh_option] [-P port] [-S program]
[[user#]host1:]file1 ... [[user#]host2:]file2

The stuff between square brackets is usually optional. Hence, you don't need to provide a -B option for example.
Nested brackets are for optional things within optional things and you can see the difference in the -c and file specification:
The [-c cipher] is optional but, if you provide -c, you must also provide the cipher bit. The entire thing within the brackets is a single atomic unit, either there or not there.
For [[user#]host1:]file1, the file1 bit is absolutely needed because there are no bracket around it. You can optionally prefix that with a remote location specifier. If you do, the host1: bit is required but the user# bit is optional. So, any of file1, host1:file1, or user#host1:file1 is allowed.

Related

getopts & preventing accidentally interpreting short options as arguments

Here's a toy example that shows what I mean:
while getopts "sf:e:" opt; foundOpts="${foundOpts}${opt}" ; done
echo $foundOpts
problem is that getopts isn't particularly smart when it comes to arguments. for example, ./myscript.sh -ssssf will output option requires an argument -- f. That's good.
But if someone does ./myscript.sh -ssfss by mistake, it parses that like -ss -f ss, which is NOT desirable behavior!
How can I detect this? Ideally, I'd like to force that f parameter to be defined separately, and allow -f foo or -f=foo, but not -sf=foo or -sf foo.
Is this possible without doing something hairy? I imagine I could do something with a RegEx, along the lines of match $# against something like -[^ef[:space:]]*[ef]{1}[ =](.*), but I'm worried about false positives (that regex might not be exactly right)
Thanks!
Here's what I've come up with. It seems to work, but I imagine the RegEx could be simplified. And I imagine there are edge cases I've overlooked.
validOpts="sf:e:"
optsWithArgs=$(echo "$validOpts" | grep -o .: | tr -d ':\n')
# ensure that options that require (or have optional) arguments are not combined with other short options
invalidOptArgFormats=( "[^$optsWithArgs[:space:]]+[$optsWithArgs]" "[$optsWithArgs]([^ =]|[ =]$|$)" )
IFS="|" && invalidOptArgRegEx="-(${invalidOptArgFormats[*]})"
[[ "$#" =~ $invalidOptArgRegEx ]] && echo -e "An option you provided takes an argument; it is required to have its option\n on a separate - to prevent accidentally passing an opt as an argument.\n (You provided ${BASH_REMATCH[0]})" && exit 1

How does the time module interpret a utility?

The man pages for the time module mention that the command can be used on "utilities".
# time usage from man pages
time [-al] [-h | -p] [-o file] utility [argument ...]
What is meant with "utility" here? Does it simply mean "command"?
If so, I'm confused by the following example, because there are several built-in command present: for, do and done (according to man pages for builtin commands). Am I right to assume that time interprets for i in {1..1000}; do var=${var}foo; done; as one "utility" here? Or does time interpret a "utility" as everything that follows the command if time doesn't appear again, else measuring a new "utility"?
var=; time for i in {1..1000}; do var=${var}foo; done; var=; time for i in {1..1000}; do var+=foo; done

rename output file using split function on mac osx

I am trying to split a large file in a chunk of 16 lines in each output file. I can do that using split -l 16 q1.txt new. But I want the output to be like ratio1.txt, ratio2.txt, ......ratio100.txt etc. So I tried: split -l 16 -d --additional-suffix=.txt q1.txt ratio
Then I get this error message on my mac:
split: illegal option -- d
usage: split [-a sufflen] [-b byte_count] [-l line_count] [-p pattern]
[file [prefix]]
Can anybody please help me to get the desired output file strings? Thank you.
If you check man split you'll find that the argument --additional-suffix=SUFFIX is not supported in this version.
To achieve what I understand you want you'll need an Automator script or a shell script, e.g.:
#!/bin/sh
DONE=false
until $DONE; do
for i in $(seq 1 16); do
read line || DONE=true;
[ -z "$line" ] && continue;
lines+=$line$'\n';
done
ratio=${lines::${#lines}-10}
(cat "Ratio"; echo "$ratio .txt";)
#echo "--- DONE SPLITTING ---";
lines=;
done < $1

Bash variable returns "command not found" in OSX Terminal

I tried using some variables to rename a few files, but it failed miserably. I've tried different ways of getting it to work, but to no avail. As far as I understand the documentation, this is the correct way of doing things - however now I'm stumped...
Here's the code (as written in the file rename_prefix.sh):
#!/bin/sh
NEWPREF="LALA"
OLDPREF="LULU"
for f in $OLDPREF*; do mv $f $(echo $f | sed 's/^$OLDPREF/$NEWPREF/g'); done
Here's the error message:
usage: mv [-f | -i | -n] [-v] source target
mv [-f | -i | -n] [-v] source ... directory
Initially I thought the problem lay in using variables with what I assume are the regular expressions, but as can be seen from the error messages, the problem lies where the variables are first declared.
What's going on here?
This can be done entirely in the shell, which also avoids the possible problem of escaping metacharacters for the sed substitution patterns. It is also blazingly fast because it saves two forks per file renamed.
NEWPREF="LALA"
OLDPREF="LULU"
for f in "$OLDPREF"*; do
mv "$f" "$NEWPREF${f#$OLDPREF}"
done
If you want to learn more about removing suffixes and prefixes from shell variable values, read up the POSIX spec on parameter expansion (which all of zsh, ksh, mksh, and bash support).
PS: The only way you can get an error like rename_prefix.sh: line 2: NEWPREF: command not found is if you had whitespace after NEWPREF and before the =. It looks very much like your program as posted is not exactly the program you ran. Did you type it instead of cut'n'paste it?
Alright so assuming you don't require POSIX, and guessing about certain other details, here's the same thing with general corrections applied.
#!/bin/bash
newpref=LALA
oldpref=LULU
shopt -s nullglob
for f in "$oldperf"*; do
mv -- "$f" "${f/#"$oldpref"/$newpref}"
done
or POSIX
#!/bin/sh
newpref=LALA
oldpref=LULU
for f in "$oldpref"*; do
[ -e "$f" ] || break
mv -- "$f" "${newpref}${f#"$oldpref"}"
done

How to parse arguments in Bash when switched AND switchless syntax is used?

I've got a bash script that can take arguments in a variety of different formats:
Format 1: myscript.sh value1 value2 [value3 value4] -p -g (no switches/flags on options that have arguments, with switches for options without arguments, which strings correspond to which values is determined partially by the ordering the values are given in and partially by regex-matching on the content of the strings)
Format 2: myscript.sh -s value1 -t value2 [-v value3 -w value4] -p -g (standard options-with-and-without-args format, easily handled by getopts)
Format 3: myscript.sh --longopt value1.... etc. (standard long-options-with-and-without args format).
Here's the stupid part: The syntaxes can be combined: myscript.sh -p value1 value3 --longopt value4 -t value2 -g should be valid, with value1 and value3 being detected by regex or relative position to the other args.
This script is used by dozens of teams in different ways, most of them automated, and everyone wants legacy compatibility with thier usage method to be preserved. I have a massive, ugly, totally manual option parser to handle all three different syntaxes. Every time I need to add a single option and preserve compatibility, I feel like I need a glass of vodka first.
My question:
Is there any utility in Bash/Unix that can parse option syntaxes like this one simply, legibly, and robustly? My alternatives, at this point, are to keep wrestling with the manual parser, or just embed a bunch of Python/optparse code in the script and use that.
have you tried getopts ?
while getopts "s:t" OPTION
do
case $OPTION in
s)
VALUE1=$OPTARG
;;
t)
VALUE2=$OPTARG
;;
exit
;;
?)
#Other stuff
esac
done

Resources