Does jq support muliple -f options? - jq

==> main.jq <==
def myflattern:
.[];
==> main2.jq <==
myflattern
Given the above jq files, I see the following output. So jq does not support multiple -f? Thanks.
$ jq -f main.jq -f main2.jq <<EOF
[ "a", "b", "c" ]
EOF
parse error: Invalid numeric literal at line 2, column 0
$ jq -f <(cat main.jq main2.jq) <<EOF
[ "a", "b", "c" ]
EOF
"a"
"b"
"c"

As pointed out by #OguzIsmail, jq does not support more than one occurrence of -f per invocation, but there are potentially two (complementary) workarounds:
If your shell allows it, you can use process substitution:
jq -f <(cat ....) ...
You can use the jq module system.
Note that there can be only one "main" in a jq program, and that jq modules can only include function definitions.

Related

How to replace a string in jq? I tried the function sub and it fails

I am using jq compiled from sources, and I do this
jq -r '.transaction_details[]|[.payer_info.payer_name.alternate_full_name]' transactions.txt | grep -i godaddy
"GoDaddy.com, LLC"
The issue is that I need to replace the "," inside Godaddy, and it fails:
jq -r '.transaction_details[]|[.payer_info.payer_name.alternate_full_name|=sub(",";"-")]' transactions.tx
How do I replace a string with another inside a single member?
I also tried with
jq -r "walk(if type == "string" then gsub(","; "-") else . end)"
and it fails.
Given the paucity of details in the question, perhaps the only thing that can be said with any degree of confidence is that the query using walk should, in a bash or bash-like environment, be:
jq -r 'walk(if type == "string" then gsub(","; "-") else . end)'
In a Windows environment, there is much to be said for using jq’s -f command-line option.
You need add some parenthesis :
jq -r '.transaction_details[]|
[ .payer_info.payer_name.alternate_full_name | (.|=sub(",";"-") )
] '

What is the easiest way for grepping the 'man grep' for flags

I do use grep a lot, but I would love to improve a bit.
Regarding the question. I wanted to narrow the man entry to find the explanation of what the -v in grep -v 'pattern' filename stood for, mainly this:
-v, --invert-match
Selected lines are those not matching any of the specified patterns.
Thus, to find the next five lines after the line which contains -v I tried:
man grep | grep -A 5 -v
and
man grep | grep -A 5 '-v'
but they return:
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
[-e pattern] [-f file] [--binary-files=value] [--color=when]
[--context[=num]] [--directories=action] [--label] [--line-buffered]
[--null] [pattern] [file ...]
This confuses me since:
man grep | grep -A 5 'Selected'
and
man grep | grep -A 5 Selected
do work.
What is wrong in my approach? Is there any easier way to achieve what I need?
One approach is to parse the Info documents for the command directly. If you run info grep (or other command) you will often find much more detailed and better-structured documentation, which will let you pin-point just the section you need.
Here's a function that will print out the relevant Info section for an option/variable/etc:
info_search() {
info --subnodes "$1" -o - 2>&- \
| awk -v RS='' "/(^|\n)(‘|'|\`)$2((,|\[| ).*)?(’|')\n/"
}
This should work on Linux/macOS/BSD. Output is like:
$ info_search grep -v
‘-v’
‘--invert-match’
Invert the sense of matching, to select non-matching lines. (‘-v’
is specified by POSIX.)
$ info_search gawk RS
'RS == "\n"'
Records are separated by the newline character ('\n'). In effect,
every line in the data file is a separate record, including blank
...
$ info_search bash -i
`-i'
Force the shell to run interactively. Interactive shells are
...

When it is allowed to omit the dot filter in jq?

I do not understand, when it is allowed to omit the dot expression.
It is possible to convert every line of raw input into a JSON string:
$ echo -e "a\nb" | jq -Rc .
"a"
"b"
In that example it makes no difference, when the dot expression is missing:
$ echo -e "a\nb" | jq -Rc
"a"
"b"
Next I can read the output from the first jq and slurp it into an array:
$ echo -e "a\nb" | jq -Rc . | jq -sc .
["a","b"]
Here it makes also no difference, when I omit the dot expression:
$ echo -e "a\nb" | jq -Rc . | jq -sc
["a","b"]
But when I omit both dot expressions, I get an usage error and an empty array as result:
$ echo -e "a\nb" | jq -Rc | jq -sc
jq - commandline JSON processor [version 1.5]
Usage: jq [options] <jq filter> [file...]
...
[]
Why?
Before directly answering the question, I'd like to clarify that:
It is always acceptable to specify a filter explicitly.
Some versions of jq expect that a filter will be specified explicitly.
Different versions of jq behave differently in the absence of an explicit filter.
The main idea guiding jq's evolution with regard to interpreting the absence of a filter intelligently has been that if there's something to read on STDIN, and if a filter has not been specified explicitly, and if it looks like you meant ., then assume you did mean ..
The answer to the question, then, is that the perplexing behavior noted in the question is a bug in a particular version of jq.
(Or if you like, the perplexing behavior reflects the difficulties that arise when developers seek to endow software with the ability to read your mind.)
By the way, the bug has been fixed:
$ jq --version
jq-1.5rc2-150-g1740fd0
$ echo -e "a\nb" | jq -Rc | jq -sc
["a","b"]
The answer is in the rest of the text
Usage: jq [options] <jq filter> [file...]
A filter should be mandatory then, a filter takes an input and produces an output, but in many times you dont need to produce an output and just want the result printed so the default was . (see the issue believe introduced in 1.5, before you must had to include the filter)
so it should be the same if . is the default filtering, unfortunately is how pipe is reading stdin and stout. You can read the details in the GitHub issue
Maybe we should print the usage message only when the program is empty, and stdin and stdout are both terminals? That is, assume . when stdin is not a terminal or when stdout is not a terminal.
so the rule is :
if you want to be perfectionist always use a filter even if . is the filter you want
if you want the result of your command to be the input of another pipe, you must indicate the filter, again if you just want the same result to be taken as input of the next command.
so the same
echo -e "a\nb" | jq -Rc > test.txt will produce an error but echo -e "a\nb" | jq -Rc . > test.txt will write the result of the command into the file

UNIX: Using awk commands to filter lists?

I'm wondering what is the syntax error in my command I'm using.
In the current directory I use the command ls -l to retrieve file permissions in my directory.
How would I do a query to see which files are readable, writeable, and executable by the user and then print a filtered list using awk?
I know the bits I'm interested in are the second, third, and fourth.
For example,
-rw-r----- .. .. .. ..
or
drw-r----- .. .. .. ..
I have an awk command as follows:
ls -l | awk '{if{$1 == /.rwx....../}print "line"}'
I've tried many things but there's still a syntax error.
Any help is greatly appreciated! Thanks in advance!
The operator used to check if a string matches a regular expression is ~, not ==. Also, use () around the condition in the if statement:
ls -l | awk '{ if ($1 ~ /.rwx....../) print "line" }'
I agree with Dennis; it's best to avoid piping ls and if you're going to do something, you may as well do it properly using stat:
stat -c '%A %N' * | awk '/^-rwx/ { print $2 }' | sed "s%^.\(.*\).$%\1%"
or just in awk:
stat -c '%A %N' * | awk '/^-rwx/ { print substr ($2, 2, length ($2) - 2) }'
EDIT:
The above fails with files containing spaces (sorry). This considers spaces and newline chars:
stat -c '%A %N' * | awk '/^-rwx/ {print substr($0, 13, length($0) - 13) }'

Unix search command

I need Unix search command which is used to find a particular word in a line and that line should not contain particular word.
For eg,
Line 1: Java is my World.
Line 2: Java is OOPs language.
I need unix command which returns lines contains "Java" not "World" in that line.
Expected Output:
Java is OOPs language.
Thanks,
Srinivasan R.
Use grep:
cat <File> | grep 'Java' | grep -v 'World'
The -v option inverts selection (i.e. lines NOT containing pattern)
You could also do it with awk and give both conditions together:
cat <File> | awk '/Java/ && !/World/'
First, list out all the files that have the word 'Java' in them and then inversely match 'World' i.e. select those lines which DO NOT have 'World' in them:
cat file | grep 'Java' | grep --invert-match 'World'
Command for particular word
grep -R dirname
grep -R dirname > filename (to append output)
to find a particular word in a line and also search file name where that word is present.

Resources