Why are spaces required before a curly brace in a function definition? - bash

I'm trying to create a bash script that converts a bunch of pdfs into text in order to extract some information but the shell gives me this error:
./AutoBib.sh: line 8: syntax error near unexpected token `pdftotext'
./AutoBib.sh: line 8: ` pdftotext $1 temp.txt'
Here there is an example of my function:
function doi{
pdftotext $1 temp.txt
cat temp.txt | grep doi: | cut -d: -f 2 | head -n 1 >> dois.txt
rm -rf temp.txt
}
doi $PDF
Where the variable PDF is taken in input. Before adding the function it worked, I used to write in my script:
pdftotext $PDF tempo.txt

From Bash manual:
The braces are reserved words, so they must be separated from the list
by blanks or other shell metacharacters.
function ... is an outdated syntax for defining Bash functions. Use this instead:
doi() {
...
}
Since () are meta characters, you don't need a space in this case (though spaces make your code prettier):
doi(){
...
}
Extending this a little, remember that we need a whitespace (space, tab, or newline) after { and before `}' in command grouping, like this:
{ command1; command2; ... }

You need a space after the name of your function and before the {:
function doi {
^

Related

Bash next line (\) in command causing spacing issues

I have the following function I want to call:
function print_something {
echo "test\
something\
yep"
}
when called it prints:
'test something yep'
I would like it to print:
'testsomethingyep'
I can get this to print if I do:
function print_something {
echo "test\
something\
yep"
}
but I don't think that looks great..
(Root problem is a curl command not an echo)
Consider assembling your pieces an array, and then combining them into a string later. Array definition syntax is far more forgiving -- not requiring backslashes at all, and also allowing comments on each line and between lines.
#!/usr/bin/env bash
# ^^^^- arrays and printf -v require bash, not sh
pieces=(
test # this also lets you use comments
something # and you don't need any backslashes at all!
# one can also have a full-line comment midway through your array
"space here" # plus if you want to add a literal space you can do it
)
printf -v oneword '%s' "${pieces[#]}"
echo "$oneword"
...properly emits:
testsomethingspace here
Here are three ideas:
#!/bin/bash
print_something() {
tr -d \\n <<- EOF
test
something
yep
EOF
echo
}
print_something2() {
echo "test"$(:
)"something"$(:
)"yep"
}
print_something3() {
tr -d \\t <<- EOF
test\
something\
yep
EOF
}
print_something
print_something2
print_something3
The first uses a <<- style heredoc to remove all of the leading indentation (that indentation must be hard-tabs for this to work, and coding styles that mandate the use of spaces for indentation render this solution unusable (this is one reason coding styles that mandate the use of spaces in shell scripts are IMO utterly useless)) and the extra tr to remove the newlines. (The additional echo is then needed to add the trailing newline.). The second uses the $(:) command substitution to discard all the intervening whitespace. The 3rd manually deletes all the hard tabs.

Trying to comment a source file

I am trying to comment lines of source so that something like
LANG = 'ENG';
becomes
// LANG = 'ENG';
There are over a thousand lines in the source file and 'ENG' is not unique but the entire line IS.
I gave up on wild carding the spaces and just tried the entire extant line 'as-is' but no joy.
Something like (commented shell)--
enter code here
#!/bin/bash
#if [ -n "$5" ] ; then
#if [ "$5" == "ENG" ] ; then
sed -i "s/' LANG = '\''ENG'\''/\/\/' LANG'
= '\''ENG'\''/" vc.pas > vc.out
#fi
#fi
So it reduces down to a single line. No joy whatever I try.
TIA !
Howie
This works for me, passing any whitespace through to the output:
$ echo "LANG='ENG';" | sed "s#^\(\s*LANG\s*=\s*'ENG'\s*;\)#// \1#"
// LANG='ENG';
$ echo " LANG = 'ENG' ; " | sed "s#^\(\s*LANG\s*=\s*'ENG'\s*;\)#// \1#"
// LANG = 'ENG' ;
Technically it needs double backslashes inside the double-quoted string, but because none of the sequences form a valid escape sequence, bash doesn't mind.
With GNU sed, use
sed -i "s,.*LANG *= *'ENG';.*,//&," vc.pas
where
-i - enables inline file modification
s - substitution command
, - delimiter
.*LANG *= *'ENG';.* - text containing LANG = 'ENG'; with any amount of spaces around =
//& - replaces the matched line with // and the line itself
Use a regular expression for the line selection, followed by a substitution. Put the replacement commands in a file:
$ cat dt.sed
/^LANG[[:space:]]*=[[:space:]]*'[^']*'/s;^;// ;
$
Then run sed(1) with that script:
$ echo "LANG='FOO'" | sed -f dt.sed
// LANG='FOO'
This works on a Fedora 34 system, but should work on any Linux.

How to read a file using delimiter and write in a different file line by line based on delimiter using shell script

I have a requirement, say file foo.txt which contains key-value pair like below:
vi foo.txt
a^1.0^b^2^cc^30^d^4^e^55^fg^67.0^h^8^i^99
and so on.
I have to write a shell script to put each key-value pair in different line to a different file, say goo.txt which contains:
a^1.0^
b^2^
cc^30^
D^4^
e^55^
fg^67.0^
h^8^
i^99^
I have a similar Perl script for it, but I want shell script. The Perl script is like
#! /usr/bin/perl -w
#
use strict;
use Getopt::Long;
my $filename = "";
my $Tags = "";
GetOptions ('file=s' => \$filename);
if (defined $filename and $filename ne "")
{
open (my $DATA,$filename) or die $!;
$Tags = <$DATA>;
while ($Tags =~ m/(.*?\^.*?\^)/g)
{
print "$1\n";
}
close($DATA)
}
I want a similar code using shell script. Need help to write a shell script (ksh) for my requirement.
cat filename | awk -F"^" '{split($0, a, "^"); for(i=1;i<NF;i=i+2){print a[i]"^"a[i+1]"^"}}'
You want an extra newline after each second ^.
The fields are without a ^, A character not ^ can be written as [^^].
Each two fields (any amount of letters excluding ^ followed by a ^ and again),
should be replaced by the match, followed by a newline.
sed 's/[^^]*^[^^]*^/&\n/g' foo.txt

unexpected EOF while looking for matching `'' while using sed

Yes this question has been asked many times, and in the answer it is said to us \ escape character before the single quote.
In the below code it isn't working:
LIST="(96634,IV14075295,TR14075685')"
LIST=`echo $LIST | sed 's/,/AAA/g' `
echo $LIST # Output: (96634AAAIV14075295AAATR14075685')
# Now i want to quote the list elements
LIST=`echo $LIST | sed 's/,/\',\'/g' ` # Giving error
# exit 0
Error :
line 7: unexpected EOF while looking for matching `''
line 8: syntax error: unexpected end of file
Instead of single quotes, use double quotes in sed command, and also remove the space before last backtick. If there is single quote present in the sed pattern then use an alternative enclosing quotes(ie, double quotes),
sed "s/,/\',\'/g"
And the line would be,
LIST=$(echo $LIST | sed "s/,/\',\'/g")
Don't use backticks inside the sripts instead of bacticks, use $()
You can use awk
echo $LIST
(96634,IV14075295,TR14075685')
LIST=$(awk '{gsub(/,/,q"&"q)};gsub(/\(/,"&"q)1' q="'" <<< $LIST)
echo $LIST
('96634','IV14075295','TR14075685')
To prevent problems with the single quote, I just set it to an awk variable.
consider
LIST="$(sed "s/,/\',\'/g" <<< "$LIST")"
but first and last elements probably won't get quoted completely, because of missing leading and trailing comma
btw, you don't need to subshell to sed - string matching and substitution is entirely within the capabilities of bash:
LIST="${LIST//,/\',\'}"

Egrep over multiple lines in a bash script function

I have a function to check a file against multiple long strings seperated by pipes. I want to put each string in the script on a new line so it's more readable. I've tried adding backslashes to the end of each line but they're just caught within the grep statement.
my_function () {
sudo zcat my_file.gz |
egrep -c 'my_long_string_1 |
my_long_string_2 |
my_long_string_3'
}
This does output a result, however, it's incorrect.
Use egrep like this on multiple lines:
my_function () {
sudo zcat my_file.gz |
egrep -c "my_long_string_1|\
my_long_string_2|\
my_long_string_3"
}
Make sure there is no space before or after backslash and there is no space on new lines before each pattern of egrep.

Resources