I am doing
a="$(openssl x509 -in /path/to/pemfile.pem -text -noout)";
echo ${a} |grep -a1 -b2 Signature
which works quite well if i put this line into terminal
However, if i put the very same line in a file executeme.sh, chmod +x executeme.sh, ./executeme.sh
I seems does not create the linebreaks in the variable, resulting grep to receive just one line. output is as follows on the terminal:
20- Version: 3 (0x2)
38- Serial Number: 32 (0x27)
64: Signature Algorithm: md5WithRSAEncryption
107- Issuer: C=EN, ST=a, L=b, O=c, OU=d, CN=e
244- Validity
------
[...]
The script outputs the entire certificate , as if i would only do a="$(openssl ...)"; echo ${a}
Do
echo "${a}" |grep -a1 -b2 Signature #mind the double quotes
Why doublequotes?
See [ this ] answer + [ this ] answer.
Related
Why following Linux shell command for given input (a-b [c=d.e] <f g>) gives extra element (3:'')?
Command:
echo "a-b [c=d.e] <f g>" | while IFS=" []<>=" read -a arr; do for ((i=0;i<${#arr[#]};i++)) do echo "${i}:'${arr[${i}]}'"; done; done
Expected output:
0:'a-b'
1:'c'
2:'d.e'
3:'f'
4:'g'
Actual output:
0:'a-b'
1:'c'
2:'d.e'
3:''
4:'f'
5:'g'
With your shown samples only(in case you are ok with awk). To get your expected output, you could do this in a single awk itself, please try following once. Simple explanation: would be, creating different field separators as per shown samples/need of OP and then traversing through all fields of current line(s) and printing only those which are required.
echo "a-b [c=d.e] <f g>" |
awk -v s1="\'" -F'[ \\[=\\]><]' '{for(i=1;i<=NF;i++){if($i){print count++":"s1 $i s1}}}'
With shown samples, output will be as follows.
0:a-b
1:c
2:d.e
3:f
4:g
I'm studying bash scripting and I'm stuck fixing an exercise of this site: https://ryanstutorials.net/bash-scripting-tutorial/bash-variables.php#activities
The task is to write a bash script to output a random word from a dictionary whose length is equal to the number supplied as the first command line argument.
My idea was to create a sub-dictionary, assign each word a number line, select a random number from those lines and filter the output, which worked for a similar simpler script, but not for this.
This is the code I used:
6 DIC='/usr/share/dict/words'
7 SUBDIC=$( egrep '^.{'$1'}$' $DIC )
8
9 MAX=$( $SUBDIC | wc -l )
10 RANDRANGE=$((1 + RANDOM % $MAX))
11
12 RWORD=$(nl "$SUBDIC" | grep "\b$RANDRANGE\b" | awk '{print $2}')
13
14 echo "Random generated word from $DIC which is $1 characters long:"
15 echo $RWORD
and this is the error I get using as input "21":
bash script.sh 21
script.sh: line 9: counterintelligence's: command not found
script.sh: line 10: 1 + RANDOM % 0: division by 0 (error token is "0")
nl: 'counterintelligence'\''s'$'\n''electroencephalograms'$'\n''electroencephalograph': No such file or directory
Random generated word from /usr/share/dict/words which is 21 characters long:
I tried in bash to split the code in smaller pieces obtaining no error (input=21):
egrep '^.{'21'}$' /usr/share/dict/words | wc -l
3
but once in the script line 9 and 10 give error.
Where do you think is the error?
problems
SUBDIC=$( egrep '^.{'$1'}$' $DIC ) will store all words of the given length in the SUBDIC variable, so it's content is now something like foo bar baz.
MAX=$( $SUBDIC | ... ) will try to run the command foo bar baz which is obviously bogus; it should be more like MAX=$(echo $SUBDIC | ... )
MAX=$( ... | wc -l ) will count the lines; when using the above mentioned echo $SUBDIC you will have multiple words, but all in one line...
RWORD=$(nl "$SUBDIC" | ...) same problem as above: there's only one line (also note #armali's answer that nl requires a file or stdin)
RWORD=$(... | grep "\b$RANDRANGE\b" | ...) might match the dictionary entry catch 22
likely RWORD=$(... | awk '{print $2}') won't handle lines containing spaces
a simple solution
doing a "random sort" over the all the possible words and taking the first line, should be sufficient:
egrep "^.{$1}$" "${DIC}" | sort -R | head -1
MAX=$( $SUBDIC | wc -l ) - A pipe is used for connecting a command's output, while $SUBDIC isn't a command; an appropriate syntax is MAX=$( <<<$SUBDIC wc -l ).
nl "$SUBDIC" - The argument to nl has to be a filename, which "$SUBDIC" isn't; an appropriate syntax is nl <<<"$SUBDIC".
This code will do it. My test dictionary of words is in file file. It's a good idea to get all words of a given length first but put them in an array not in var. And then get a random index and echo it.
dic=( $(sed -n "/^.\{$1\}$/p" file) )
ind=$((0 + RANDOM % ${#dic[#]}))
echo ${dic[$ind]}
I am also doing this activity and I create one simple solution.
I create the script.
#!/bin/bash
awk "NR==$1 {print}" /usr/share/dict/words
Here if you want a random string then you have to run the script as per the below command from the terminal.
./script.sh $RANDOM
If you want the print any specific number string then you can run as per the below command from the terminal.
./script.sh 465
cat /usr/share/dict/american-english | head -n $RANDOM | tail -n 1
$RANDOM - Returns a different random number each time is it referred to.
this simple line outputs random word from the mentioned dictionary.
Otherwise as umläute mentined you can do:
cat /usr/share/dict/american-english | sort -R | head -1
Hi I'm trying to add text to the 1st line of a file using sed
so far iv'e tried
#!/bin/bash
touch test
sed -i -e '1i/etc/example/live/example.com/fullchain.pem;\' test
And this dosn't work
also tried
#!/bin/bash
touch test
sed -i "1i ssl_certificate /etc/example/live/example.com/fullchain.pem;" test
this dosn't seem to work either
oddly when I try
#!/bin/bash
touch test
echo "ssl_certificate /etc/example/live/example.com/fullchain.pem;" > test
I get the 1st line of text to appear when i use cat test
but as soon as i type sed -i "2i ssl_certificate_key /etc/example/live/example.com/privkey.pem;"
I can't see the information that i sould do on line 2 this being ssl_certificate_key /etc/example/live/example.com/privkey.pem;
so my question to summerise
Can text be inserted into the 1st line of a newly created file using sed?
If yes whats the best way of inserting text after the 1st line of text?
Suppose you have a file like this:
one
two
Then to append to the first line:
$ sed '1 s_$_/etc/example/live/example.com/fullchain.pem;_' file
one/etc/example/live/example.com/fullchain.pem;
two
To insert before the first line:
$ sed '1 i /etc/example/live/example.com/fullchain.pem;' file
/etc/example/live/example.com/fullchain.pem;
one
two
Or, to append after the first line:
$ sed '1 a /etc/example/live/example.com/fullchain.pem;' file
one
/etc/example/live/example.com/fullchain.pem;
two
Note the number 1 in those sed expressions - that's called the address in sed terminology. It tells you on which line the command that follows is to operate.
If your file doesn't contain the line you're addressing, the sed command won't get executed. That's why you can't insert/append on line 1, if your file is empty.
Instead of using stream editor, to append (to empty files), just use a shell redirection >>:
echo "content" >> file
Your problem stems from the fact that sed cannot locate the line you're telling it to write at, for example:
touch test
sed -i -e '1i/etc/example/live/example.com/fullchain.pem;\' test
attempts to write to insert at the line 1 of test, but that line doesn't exist at this point. If you've created your file as:
echo -en "\n" > test
sed -i '1i/etc/example/live/example.com/fullchain.pem;\' test
it would not complain, but you'd be having an extra line. Similarly, when you call:
sed -i "2i ssl_certificate_key /etc/example/live/example.com/privkey.pem;"
you're telling sed to insert the following data at the line 2 which doesn't exist at that point so sed doesn't get to edit the file.
So, for the initial line or the last line in the file, you should not use sed because simple > and >> stream redirects are more than enough.
Your command will work if you make sure the input file has at least one line:
[ "$(wc -l < test)" -gt 0 ] || printf '\n' >> test
sed -i -e '1 i/etc/example/live/example.com/fullchain.pem;\' test
To insert text to the first line and put the rest on a new line using sed on macOS this worked for me
sed -i '' '1 i \
Insert
' ~/Downloads/File-path.txt
First and Last
I would assume that anyone who searched for how to insert/append text to the beginning/end of a file probably also needs to know how to do the other also.
cal | \
gsed -E \
-e '1i\{' \
-e '1i\ "lines": [' \
-e 's/(.*)/ "\1",/' \
-e '$s/,$//' \
-e '$a\ ]' \
-e '$a\}'
Explanation
This is cal output piped to gnu-sed (called gsed on macOS installed via brew.sh) with extended RegEx (-E) and 6 "scripts" applied (-e) and line breaks escaped with \ for readability. Scripts 1 & 2 use 1i\ to "at line 1, insert". Scripts 5 & 6 use $a\ to "at line <last>, append". I vertically aligned the text outputs to make the code represent what is expected in the result. Scripts 3 & 4 do substitutions (the latter applying only to "line <last>"). The result is converting command output to valid JSON.
output
{
"lines": [
" October 2019 ",
"Su Mo Tu We Th Fr Sa ",
" 1 2 3 4 5 ",
" 6 7 8 9 10 11 12 ",
"13 14 15 16 17 18 19 ",
"20 21 22 23 24 25 26 ",
"27 28 29 30 31 ",
" "
]
}
For help getting this to work with the macos/BSD version of sed, see my answer here.
Hello folks!
First a code I have now:
for CLSGRPID in `${${`/usr/bin/snmpwalk \
-v 1 -c $COMM $HOST $OID.11.1.1.1`##*:}%\n} | xargs` ; do
I'd like to first process
/usr/bin/snmpwalk -v 1 -c $COMM $HOST $OID.11.1.1.1
which used alone returns lines
.2.3.1.2.1.5.11.1.1.1.1 = INTEGER: 1
.2.3.1.2.1.5.11.1.1.1.2 = INTEGER: 2
.2.3.1.2.1.5.11.1.1.1.3 = INTEGER: 3
and then for every return line I'd like to cut it like ${line##*:} and then from the other side ${line%\n} and then all of those lines put to xargs and process it.
So requested output would be
1 2 3
Is it possible? Please get me some ideas how to do it.
net-snmp commands have many options that modify their behaviour and output. I recommend that you read the man pages for each of snmpcmd, snmpwalk, and snmp.conf.
Check the -O option group in snmpwalk (see below).
The -Oqv combination results in a column with just the numbers:
$ clsgrpids=$(
/usr/bin/snmpwalk -Oqv -v 1 -c $COMM $HOST $OID.11.1.1.1
)
$ echo "$clsgrpids"
1
2
3
Remove the quotes to let the shell print a single line:
$ echo $clsgrpids
1 2 3
Here are the remaining options in the -O option group that control the output for snmpwalk:
-O OUTOPTS
Toggle various defaults controlling output display:
0: print leading 0 for single-digit hex characters
a: print all strings in ascii format
b: do not break OID indexes down
e: print enums numerically
E: escape quotes in string indices
f: print full OIDs on output
n: print OIDs numerically
q: quick print for easier parsing
Q: quick print with equal-signs
s: print only last symbolic element of OID
S: print MIB module-id plus last element
t: print timeticks unparsed as numeric integers
T: print human-readable text along with hex strings
u: print OIDs using UCD-style prefix suppression
U: don't print units
v: print values only (not OID = value)
Verification (actual running code)
$ snmpwalk -Ov -v1 -c public localhost sysUptime
Timeticks: (66595) 0:11:05.95
$ snmpwalk -Oqv -v1 -c public localhost sysUptime
0:0:11:35.13
$ snmpwalk -Otqv -v1 -c public localhost sysUptime
70012
You can use awk.
for CLSGRPID in `/usr/bin/snmpwalk -v 1 -c $COMM $HOST $OID.11.1.1.1 | awk '{print $NF}'`; do
echo $CLSGRPID
done
Not sure why this is failing..
./testme.sh
Before Loop
SSL1: /root/a.txt SHA256(/root/a.txt)= 92b165232fbd011da355eca0b033db22b934ba9af0145a437a832d27310b89f9
SSL2: /root/b.txt SHA256(/root/b.txt)= f0f9c277cf17429957daf6594714cc5470ac5c474ba5ac50319185477a174799
different
cp a.txt b.txt
./testme.sh
Before Loop
SSL1: /root/a.txt SHA256(/root/a.txt)= 92b165232fbd011da355eca0b033db22b934ba9af0145a437a832d27310b89f9
SSL2: /root/b.txt SHA256(/root/b.txt)= 92b165232fbd011da355eca0b033db22b934ba9af0145a437a832d27310b89f9
different
Checksums, and the same, but reported different :|
#!/bin/bash
#
# OPENSSL=/usr/bin/openssl
OPENSSL=/usr/local/openssl/bin/openssl
HOME=/root
ENCRYPT=sha256
SSL1=$($OPENSSL $ENCRYPT $HOME/a.txt)
SSL2=$($OPENSSL $ENCRYPT $HOME/b.txt)
## DEBUG
echo "SSL1: $HOME/a.txt $SSL1"
echo "SSL2: $HOME/b.txt $SSL2"
if [ "$SSL1" = "$SSL2" ]
then
echo "same"
else
echo "different"
fi
I was literally working on this today. Here's a one-liner tested on OSX
diff <(openssl sha1 index.css | awk {'print $2'}) <(openssl sha1 original_source/index.css | awk {'print $2'})
No output on success; outputs both hashes on fail.
$SSL1 contains more than just the hash of the file; it also contains the string SHA256(/root/a.txt)=, which includes the filename. And likewise for $SSL2. So naturally they're not equal, since they contain different filenames.
To get just the hash, there are a few approaches you can take. I think the simplest is just to pipe it to grep:
SSL1=$($OPENSSL $ENCRYPT $HOME/a.txt | grep -o '[0-9a-f]*$')
SSL2=$($OPENSSL $ENCRYPT $HOME/b.txt | grep -o '[0-9a-f]*$')
Look closer. The result includes the filename.