Proper formatting for --help output - c

I'm writing a command-line program in C, and I'd like to implement a --help option to show the usual stuff like available options and what they do, and usage examples.
Is there a proper method for formatting the text that is displayed in the help? Or do I just do my best to make it look nice?
I looked at some random programs on SourceForge to see how they did it, and most just used a bunch of printf()s to output pre-formatted (as far as spacing and indentation) text.
Is groff or troff appropriate here? I have come across those applications in my Googlings, which seem to be some kind of typesetting programs, but I am unfamiliar with them.

Generally speaking more people are concerned that the program works as stated than how well the help is displayed. Do your best (effort is always appreciated) with printf and get on with it and your life. You have bigger fish to fry.

Don't sweat the format that much. On the other hand, you yourself will be using it from time to time. Include such pertinent details as the program's purpose, relevant options, and some examples. A blank line to clearly delineate them should be good.
On an unrelated note, if your doing command line options in c, use the gnu getopts c library. It makes it much, much easier. And as a bonus, you don't get mugged by the details of parsing the command line.

Using groff or troff is overkill. Decently laid out printf() formatting is sufficient. If you layout your help messages systematically, it is easy enough to manage. The most complex set of options I have in any of my programs has:
static const char optlist[] = "a:cd:e:f:ghi:o:p:st:u:vxyz:A:BCD:E:F:G:HIJL:M:N:O:PQ:RS:TUVX:YZ:";
static const char usestr[] =
"[-cghsvxyY] [-d dbase] [-f file] [-e 'SQL stmt'] ['SQL stmt' ...]\n"
"Other options: [-CJPRU][-BHITV][-D delim][-E escape][-Q quote][-F format]\n"
" [-A date][-i file][-o file][-L qlimit][-N number][-M FIFO]\n"
" [-Z debug][-G eor][-t table][-p password][-u username]\n"
" [-a ibase][-X record=rectag,recset=settag,header=hdrtag]\n"
" [-O orderby][-S skip][-z number]\n"
"NB: -h gives more help!";
static const char fullhelp[] =
"\nOption summary:\n"
" -a ibase - input base (default 0; set to 10 for fields with leading zeroes)\n"
" -c - continue after errors\n"
" -d dbase - select database\n"
" -e 'SQL stmt' - execute SQL command\n"
" -f file - input file for SQLCMD\n"
" -g - debugging mode (single-step commands)\n"
" -h - print this message\n"
" -i file - input file for SQLRELOAD\n"
" -o file - output file for SQLUNLOAD\n"
" -p password - password for connection (beware security implications!)\n"
" -s - silent mode\n"
" -t table - name of table (for SQLRELOAD or SQLUNLOAD)\n"
" -u username - username for connection (beware security implications!)\n"
" -v - verbose mode\n"
" -x - trace mode\n"
" -y - enable history\n"
" -z number - set debugging level for syntax and lexical analyzers\n"
" -A date - set date format (eg dd-mm-yyyy for $DBDATE=dmy4-)\n"
" -B - operate in benchmark mode (implies -x and times SQL)\n"
" -C - operate as SQLCMD\n"
" -D delim - set field delimiter (default $DBDELIMITER or pipe)\n"
" -E escape - set escape character (default $DBESCAPE or backslash)\n"
" -F format - set output format (default SELECT; alternatives include:\n"
" UNLOAD, FIXED, FIXSEP, FIXDEL, CSV, XML, HTML)\n"
" -G eor - set EOR (end of record) character string (default $DBNEWLINE or newline)\n"
" -H - include column headings in output\n"
" -I - interactive mode (after executing command line)\n"
" -J - simulate isql/dbaccess; accept [database|-] [script|-]\n"
" -L qlimit - limit on number of rows returned by query\n"
" -M FIFO - monitor FIFO for input commands\n"
" -N number - size of transaction under RELOAD\n"
" (default 1024; 0 means no sub-transactions)\n"
" -O col1,... - order by these columns (SQLUNLOAD)\n"
" -P - operate as SQLUPLOAD (not implemented yet)\n"
" -Q quote - set quote character (default $DBQUOTE or double quote)\n"
" -R - operate as SQLRELOAD\n"
" -S skip - initial rows to skip (SQLRELOAD)\n"
" -T - include column types in output\n"
" -U - operate as SQLUNLOAD\n"
" -V - print version and exit\n"
" -X xmloptions - configure the XML output\n"
" recset='recsettag',record='recordtag',header='headertag'\n"
" -Y - do not enable history, even in interactive mode\n"
" -Z debug - set debugging level (SQLCMD must be compiled with debugging enabled)\n"
;
Yes, it needs to go to long options before long.

Related

Postgres database backup error - special character in password

I'm trying to take a PostgreSQL backup with pg_dump. But I'm not able to take it due to the following error.
I have successfully taken backups for different IP addresses without the special character # in it.
command used and working
sudo /usr/bin/pg_dump --file "/home/myusername/my_first_db.backup" \
--verbose --format=t --blobs -v \
--dbname postgresql://postgres:myfirstpassowrd#112.112.113.114:5432/my_first_db
command used and not working
sudo /usr/bin/pg_dump --file "/home/myuser/xyz_db/DB_BACKUP/db_file.backup" \
--verbose --format=t --blobs -v \
--dbname postgresql://111.222.333.444:5432/prod_live?password=123th#123th4&user=postgres
sudo /usr/bin/pg_dump --file "/home/myuser/xyz_db/DB_BACKUP/db_file.backup" \
--verbose --format=t --blobs -v \
--dbname postgresql://111.222.333.444:5432/prod_live?password=123th%40123th4&user=postgres
Error I'm getting:
[4] 8555
myuser#myuser:~$ pg_dump: [archiver (db)] connection to database "prod_live" failed: FATAL: password authentication failed for user "root"
FATAL: password authentication failed for user "root"
I cannot change the password, because it is production.
As I can see...
Unquoted character & in your command line sends the task to background as described, for example, here: Linux: Start Command In Background. So anything after & character ignored (or interpreted as separate command) by *nix shell.
Solution
Just try to quote the whole string like this:
sudo /usr/bin/pg_dump --file "/home/myuser/xyz_db/DB_BACKUP/db_file.backup" \
--verbose --format=t --blobs -v \
--dbname 'postgresql://111.222.333.444:5432/prod_live?password=123th#123th4&user=postgres'
Explanation
In the output provided by you the line [4] 8555 means Background job #4 with process ID 8555 was started
And single quotes around the string allows to interpret it "as-is", without parameters substitution and other special characters interpreting.
PS: Use $'...' syntax to translate special escaped characters like \n \t \uxxxx and others.
There is several examples:
$ echo abc&defgh
[1] 3426
abc
defgh: command not found
[1]+ Done echo abc
As you can see the output is like to provided by you in the part [x] xxxx
$ echo 'abc&defgh'
abc&defgh
In this case command echo prints exactly what you want
And last but not least:
$ echo '1: abc&\ndefgh'; echo $'2: abc&\ndefgh'
1: abc&\ndefgh
2: abc&
defgh

BCP command in Linux doesn't return the proper error code

In Linux/Unix based systems, whenever we execute a command in the shell and we echo the $?, the return value is 0 when its a success and the return value is 1 if the command fails.
So, if I am using the BULK COPY utility called BCP for SQL Server, and if the command fails when there is an error with the source file. For example, if I execute a bcp command like this.
/opt/bin/bcp <tablename> in <source_file> -S -U -P -D
and it says. "0 Rows Copied". It might be due to some errors in the source file. And, after that I do a echo $?. The value returned is still 0.
Is there a way we can capture the return value as 1, when encountered an error?
Thanks.
BCP doesn't document any return value. That's a shortcoming. What you can do is redirect output to a file, and look for error indications (probably, the text "Error").
To add a bit more detail to TT.'s answer, I write the bcp output to another file and then grep through it. My code looks like...
/opt/mssql-tools/bin/bcp "$TABLENAME" in $f \
-S $DEST_IP \
-U $USER -P $PASSWORD \
-d $DEST_DB \
-c \
-t "\t" \
-e $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcperror.log \
| tee $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcprun.log
# note here that I preserve the bcp output to can later in script
# look for error messages in the bcp process run itself (manually done since bcp does not throw error codes)
echo -e "\n Checking for error messages in bcp output\n"
if grep -q "Error" $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcprun.log
then
echo -e "\n\nError: error message detected in bcp process output, exiting..."
exit 255
fi
# can delete since already printing to stdout as well (and can just log the whole thing)
rm -f $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcprun.log

Bash how to enter output to an array

I have a scrip that takes input(domain) and output the domain DNS, now I want to enter this output to differentness variables, how can I do that?
read -p "Enter a vaild Domain ex:google.com"\ domain
echo
if grep -qE '^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$' <<< "$do$
then
dns=$(host -t ns "$domain" |cut -d " " -f 4);
else
echo 'Please enter a vaild domain';exit
fi
E: Also is there a way to enter input in a new line? instead in the same one.
With ANSI-C Quoting, whose form is $'string', you can implement entering input on a new line. For example:
read -p $'Enter a valid Domain ex:google.com\n' domain
Refer to ANSI-C Quoting

Opentsdb open source time series database

Is there anyone who has installed opentsdb on Ubuntu 15.04 version? If so please share the steps to be followed. I tried number of times but I am not able to install it properly.
You need to write tcollector, for example:
Step 1: create metrics:
./tsdb mkmetric proc.loadavg.1m proc.loadavg.5m
Step 2: create collector in shell script or command line.
cat >loadavg-collector.sh <<\EOF
#!/bin/bash set -e
while true; do
awk -v now=`date +%s` -v host=`hostname` \ '{ print "put proc.loadavg.1m " now " " $1 " host=" host;
print "put proc.loadavg.5m " now " " $2 " host=" host }'
/proc/loadavg sleep 15 done | nc -w 30 host.name.of.tsd PORT EOF
Then:
chmod +x loadavg-collector.sh
nohup ./loadavg-collector.sh &
It will collect data every 15 second on metrics proc.loadavg.1m and proc.loadavg.5m. Now you will be able to see graph in webinterface of opentsdb.
For detail please check the link below:
http://opentsdb.net/docs/build/html/user_guide/quickstart.html

How to use TAB as column separator in SQLCMD

SQLCMD supports the -s parameter to specify the column separator, but I couldn't figure how how to represent the tab (CHAR(9)) character. I have tried the following but both don't work:
sqlcmd -S ServerName -E -Q"select * from mytable" -s"\t" -o results.txt
sqlcmd -S ServerName -E -Q"select * from mytable" -s'\t' -o results.txt
Any ideas how to do this in SQLCMD?
In a batch file, putting a tab between the double quotes works.
sqlcmd -S ServerName -E -Q"select * from mytable" -s" " -o results.txt
to do the same in a PowerShell file use escaped double quotes wrapped around an escaped tab
sqlcmd -S ServerName -E -Q"select * from mytable" -s `"`t`" -o results.txt
It's difficult to get unformatted results from SQLCMD.
If you want to create a tab-delimited output file, BCP might be a better bet:
bcp "select * from mytable" queryout results.txt -S server -T -c
Found a good answer here: SQLCMD outfile as tab delimited text file
Open Notepad
Paste this: sqlcmd -S (local) -E -s"<TAB>" -Q "select * from sys.dm_exec_query_stats" -o MyOutput.txt -h-1 -W
Highlight <TAB>, then hit the Tab key
Save the file as MyBatch.bat
Run MyBatch.bat
I've tried numerous times to pass the actual TAB character in to SQLCMD, and I simply can't get it to take it. My favorite work-around to-date is to pass SQLCMD the ASCII "Unit Separator", which is hex 0x1F, and can be entered on the command line by typing Ctrl-_ (control underscore, which on a US keyboard becomes ctrl-shift-'-' (the '-' next to the '0' on the top row of the keyboard).
The advantage of using the 'Unit Separator' is that is is HIGHLY unlikely to be present in text of any description, and was designed specifically for this purpose (see https://en.wikipedia.org/wiki/Delimiter)
Having got SQLCMD to do that for me, I then pipe it's output though a Unix-style translate command as:
tr '\037' '\t'
The \037 is octal for the 'Unit Separator', and \t represents the tab character, 'tr' will translate BOTH of these for us, we don't need to rely on any quoting tricks in our scripts or shells.
To get 'tr' on windows, you can install the CoreUtils package from GnuWin32 (see http://gnuwin32.sourceforge.net/packages/coreutils.htm) or go heavy-weight and install a full Unix environment such as Cygwin (http://cygwin.com/).
Putting the two together we get:
sqlcmd ... -h-1 -W -k -r1 -s^_ ... | tr '\037' '\t'
and this will give you your output with tabs.
Look up the other options I've used above, they're essential for trying to get clean output from SQLCMD (in order; no headers, trim white-space, CRLF to spaces, errors to STDERR (not your output file!) and the '^_' is how the Unit Separator will appear on the command line). You'll also need to add "SET NOCOUNT ON;" to your query or sql script, otherwise you'll get the row-count as a trialling message appearing in your output!
A similar answer to one posted above, but it's simpler in a way that I think is significant.
Open your text editor
Press Tab
Highlight the chunk of whitespace (the tab) created
Copy and paste that into the spot in your SQL command
Even though this tab is represented as a wide chunk of whitespace, it is a single character.
The other answer had some unnecessary stuff about pasting the whole command with "<TAB>" in it. I think that throws people off (it certainly threw me off).
To work in the Command Prompt window instead in batch file, this is the only way that I have found to solve it:
sqlcmd -S ServerName -E -d database_Name -Q"select col1, char(9), col2, char(9), col3, char(9), col4, char(9), col5 from mytable" -o results.txt -W -w 1024 -s "" -m 1
tldr: use ALT+009 the ascii tab code for the separator character
In the example, replace {ALTCHAR} with ALT+009 (hold the ALT key and enter the digits 009)
sqlcmd -E -d tempdb -W -s "{ALTCHAR}" -o junk.txt -Q "select 1 c1,2 c2,3 c3"
Edit junk.txt. Tabs will be between columns.
For other command line options:
sqlcmd -?
Note: The shell converts the ALT char to ^I, but if you try the command by typing -s "^I", you won't get the same results.
Use dynamic sql with CHAR(9):
SET #cmd ='SQLCMD -S MyServer -d MyDatabase -E -W -Q "SELECT * FROM MyTable" -s"' + CHAR(9) + '" -o "MyFilePath.txt"'
Try using horizontal scroll bars with cmd.exe or powershell. Right click shortcut and click properties for repeated use, or right click title bar and click properties after opening then click layout tab. In screen buffer size set width and height to 8000 and then unselect wrap text output on resize (important). Click ok. Then restore down by clicking button next to minimize. You should see horizontal and vertical scroll bars. You can maximize window now and scroll in any direction. Now you can see all records in database.
I had this problem while trying to run sqlcmd on terminal. I got it working by entering a tab character (copying from text editor didn't work for me).
Press cntrl + v then tab.
How to enter a tab char on command line?
To achieve this using sqlcmd you need to use the Tab character like so: \t
An example query exporting a single sql database table into a text file using a tab delimiter is as follows:
sqlcmd -S ServerName -d databaseTableName -Q "SELECT * FROM TABLE_NAME" -o C:\backups\tab_delimiter_bakup.txt -s"\t"
If on Linux then this will work as the -s (col_separator)
-s "$(printf "t" | tr 't' '\t')" or
SQLCMDCOLSEP="$(printf "t" | tr 't' '\t')" sqlcmd -S ...

Resources