I would like a bash shell script (for my Debian 12 system) which accepts multiple paths as arguments, and then checks if a file can be successfully created in each one. Then the result should be put into json format.
The command to run should be:
./checkavailable.sh /the/first/path /the/second/path
(where there could be any number of input paths given, but at least one) and I would like the output to be in the following format:
[
{ "is_available": 0, "path": "/the/first/path/" },
{ "is_available": 1, "path": "/the/second/path/" }
]
Currently, I managed to achieve this with the following script:
#!/bin/bash
# Check if first path is available
if touch $1/checkalivefile ; then
avail_path1=1
rm $1/checkalivefile
else
avail_path1=0
fi
# Check if second path is available
if touch $2/checkalivefile ; then
avail_path2=1
$2/checkalivefile
else
avail_path2=0
fi
echo "["
printf " { \"is_available\": "$avail_path1", \"path\": \"$1\" } "
printf ",\n"
printf " { \"is_available\": "$avail_path2", \"path\": \"$2\" } "
echo
echo "]"
but it's obviously a bit primitive and is hardcoded to work with x2 arguments only, and doesn't scale to additional arguments.
I could try to add a loop now. However, I came across this script, which seems to do something similar (to get disk usage in this case) but using awk instead of a loop:
#!/bin/bash
echo "["
du -s -B1 "$@" | awk '{if (NR!=1) {printf ",\n"};printf " { \"dir_size_bytes\": "$1", \"path\": \""$2"\" }";}'
echo
echo "]"
Can someone show how this approach using "awk" could be used in my case? I am very new to bash scripts, so hope to learn something.
----EDIT----
For context, the reason for generating the json output in this particular format, is because it can be interpreted directly by the input plugins in Telegraf, which can convert it automatically into fields and tags metrics for sending to a database.
Note that touch
can take multiple arguments, so touch "$@"
would already perform that command on all paths provided to your script. Depending on what is_available
actually stands for in your desired output, you could then just query if the files are actually present, are writeable, etc.
Here's an approach that still iterates over your script's arguments using a for
loop, applies touch
individually, and checks its (negated) exit code $?
. These are then fed into a simple jq script that takes care of returning a valid JSON encoding, regardless of any strange characters in the paths provided.
#!/bin/sh
for path; do ! touch "$path/dummy"; echo $?; rm -f "$path/dummy"; done |
jq -n --args '[$ARGS.positional[] | {is_available: input, path: .}]' "$@"
Note: Swallow stderr by using touch … 2>/dev/null
to silence the error messages printed on failure.
I have NFS shares mounted in various directories. I want a way to check if the connection was lost. So I want to be able to check that new files can be successfully written to these directories where the mounts are supposed to appear. […] I was only creating a dummy file before as a check that the directory was present and writable.
I'm afraid, touch
won't help you in that case, (and neither would a test
with -d
and -w
), as they won't tell you if something is mounted there or not. After all, an unmounted mountpoint may very well still be a writeable directory. Thus, rather use the df
command which lists actual mountpoints, narrow down by file system e.g. using -t nfs4
, and proceed as before.
#!/bin/sh
for path; do ! df -t nfs4 "$path" >/dev/null 2>/dev/null; echo $?; done |
jq -n --args '[$ARGS.positional[] | {is_available: input, path: .}]' "$@"
Thanks, but I receive an error "jq: command not found". [… I] don't want to install new package
There's no need to install any new packages: you can simply download and execute the binary directly. Also, keep in mind that with arbitrary input strings (which in this case is the path names which could contain almost any character), you'll have a hard time trying to properly encode them for a hand-crafted JSON output. Therefore, I strongly discourage anyone from using the following alternative in production, but for an approach that simply dumps the strings into quotes, no matter what, risking an invalid JSON output, replace (in any of the above scripts) the jq line with:
while read -r is_av; do
printf '{"is_available": %d, "path": "%s"}\n,' "$is_av" "$1"; shift
done | sed '1s/^/[/;$s/,/]/'