Missing "))" in shell script - shell

I'm really sorry I'm a total noob in shell scripting, I looked on the Internet and I didn't find the answer
=> /home/bee/Scripts/chkbsh: 11: /home/bee/Scripts/chkbsh: Syntax error: Missing '))'
#!/bin/sh
for file in $((gawk '/^#!.*( |[/])sh/{printf "%s\0", FILENAME} {nextfile}' /usr/bin/* 2>/dev/null) | xargs -0); do
checkbashisms "$file" >/dev/null 2>&1
if [ "$?" -gt 0 ]
then
sed -i 's:^#!.*/bin/sh:#!/bin/bash:' "$file";
echo "$file" has been processed!
fi
done
echo ":3"
If I change #!/bin/sh in #!/bin/bash everything is okay

You have opening double parentheses, but two single closing parentheses. Place a space after the first (, like this:
for file in $( (gawk '/^#!.*( |[/])sh/{printf "%s\0", FILENAME}
^ there
BTW, it's always good advice to test your scripts with ShellCheck, this way you could have easily spotted above error.

Try
for file in `gawk '/^#!.*( |[/])sh/{printf "%s\0", FILENAME} {nextfile}' /usr/bin/* 2>/dev/null | xargs -0`; do
checkbashisms "$file" >/dev/null 2>&1

Related

sed command results in unterminated address regex

I'm trying to search and replace a string with the sed command in linux but keep getting errors in STDERR such as
sed: -e expression #1, char 53: unterminated address regex
Here's what doing:
string="SOMEFILE.TXT SOMEFILE2.TXT SOMEFILE3.TXT"
path="/path/to/file/"
replace="TXT \] || \[ ${path}SOME"
formatted_string=`echo ${string} | sed -e "/TXT SOME/${replace}/g"`
if [ -e ${path}/${formatted_string} ]; then
The end goal is to have a formatted string to insert into the if command to look for one or more files if they exist. The string with files can vary so that's why I'm doing this. The above code works and it does find the files but I can't get rid of the error.
Thanks for any help
The right way
array=( "SOMEFILE.TXT" "SOMEFILE2.TXT" "SOMEFILE3.TXT")
path_to_file="/path/to/file/"
file_exist=
for filename in "#{array[#]}"; do
if [ -e "${path_to_file}/${filename}" ]; then
file_exist=1
fi
done
if [ -n "${file_exist:+X}" ]; then
...
or shorter (one-liner)
shopt -s extglob
if [ -e "/file/to/path/"#("SOMEFILE.TXT"|"SOMEFILE2.TXT"|"SOMEFILE3.TXT") ]; then
Can you try this code
string="SOMEFILE.TXT SOMEFILE2.TXT SOMEFILE3.TXT"
path="\/path\/to\/file\/"
replace="TXT \] || \[ ${path}SOME"
formatted_string=`echo ${string} | sed -e "s/TXT SOME/${replace}/g"`
echo $formatted_string
It sounds like all you need is something like:
if ls /path/to/file/SOMEFILE*.TXT >/dev/null 2>&1; then
at least one file exists so do whatever...
fi
or if you want to do something with the list of files:
shopt -s nullglob
files=(/path/to/file/SOMEFILE*.TXT)
if [ ${#files[#]} -gt 0 ]; then
at least one file exists so do whatever...
fi
Thanks for all the help! I ended up omitting the sed command altogether and found a more practical solution:
string="/path/to/file/SOMEFILE*.TXT"
files=$(ls ${string} 2> /dev/null | wc -l)
if [ **"$files" != "0"** ]; then
This does what I need and seems easier to read than what I was trying to do earlier.

rename file names work in command prompt but not in bash script

I'm trying to rename commands in a bash script. If I run for example:
echo /home/scientist/mySalesData/campaignData_1482386214.24417.csv | sed 's/\(.*\)\(_.*\)/mv \"&" \"\1.csv\"/' | bash
It works fine and gives me campaignData.csv in the directory /home/scientist/mySalesData/ .
However, if I put this in a bash script as follows:
for f in /home/scientist/SalesData/*; do
if [ -f "$f" ];
cp "$f" /home/scientist/SalesForce/SalesData/Backups/
echo $f$ | sed 's/\(.*\)\(_.*\)/mv \"&" \"\1.csv\"/' | bash |
fi
done
I get:
mv: cannot stat '/home/scientist/SalesData/campaignData_1482386214.24417.csv$': No such file or directory
Any help would be much appreciated!
cd "$srcdir"
for f in *; do
if [ -f "$f" ]; then
cp "./$f" "$dstdir/${f%_*}.csv"
fi
done
The % is the strip shortest suffix pattern operator.
You have a trailing $ here:
echo $f$
remove that (and quote the expansion):
echo "$f"
You could use here string too:
sed ... <<<"$f"

Redirect grep output to file

I am not sure as to why that redirection provided in the code does not work. Every time I run the script, the output file is always empty. Does anyone have an idea on that?
Thanks.
#!/bin/sh
LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`
for i in $FILES
do
# echo "Looking in $i ..."
unzip -p $i | grep -i $LOOK_FOR > output #> /dev/null
if [ $? == 0 ]
then
echo ">>>> Found $LOOK_FOR in $i <<<<"
fi
done
You may want to use >> (append) instead of > (overwrite) for redirection as:
unzip -p $i | grep -iF "$LOOK_FOR" >> output
Since you're executing this command in a loop and overwriting file output every time, it might be blank in the end if very last command with grep doesn't find any matching line in unzip output.
You have three problems
Don't try to parse the output of ls. Instead just use for i in plugins/*source*.jar The major reason is that your script will completely and utterly break on any files that have spaces in their names. See this link for a litany of reasons why not to parse ls
You need to use >> instead of > as the latter will overwrite the output file on each iteration of the loop. The former will append to it
Use more quotes! You'll want to quote your variables to make sure they aren't subjected to word splitting
Also, you can inline the if test. So putting it all together we have:
#!/bin/sh
LOOK_FOR="DefaultProblem"
for i in plugins/*source*.jar
do
# echo "Looking in $i ..."
if unzip -p "$i" | grep -i "$LOOK_FOR" >> output #> /dev/null
then
echo ">>>> Found $LOOK_FOR in $i <<<<"
fi
done
You can redirect the output of the entire loop:
#!/bin/sh
LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`
for i in $FILES ; do
# echo "Looking in $i ..." 1>&2
unzip -p $i | grep -i $LOOK_FOR
if [ $? == 0 ] ; then
echo ">>>> Found $LOOK_FOR in $i <<<<" 1>&2
fi
done > output
Note that I've redirected the diagnostic messages to stderr.
Instead of a for loop and an if conditional you can do everything in one find command
find /path/to/plugins -name "*source*.jar" -exec sh -c 'unzip -l "{}" | grep -q DefaultProblem' \; -print

In a unix box, I am taking a list of files as input. If it is found, return the path otherwise return a message "filename file not found"

I have used the find command for this, but it doesnt return any message when a file is not found.
And I want the search to be recursive and return a message "not found" when a file is not found.
Here's the code I have done so far. Here "input.txt" contains the list of files to be searched.
set `cat input.txt`
echo $#
for i in $#
do
find $HOME -name $i
done
Try this:
listfile=input.txt
exec 3>&1
find | \
grep -f <( sed 's|.*|/&$|' "$listfile" ) | \
tee /dev/fd/3 | \
sed 's|.*/\([^/]*\)$|\1|' | \
grep -v -f - "$listfile" | \
sed 's/$/ Not found/'
exec 3>&-
open file descriptor 3
find the files
see if they're on the list (use sed to
send a copy of the found ones to file descriptor 3
strip off the directory name
get a list of the ones that don't appear
add the "Not found" message
close file descriptor 3
Output looks like:
/path/to/file1
/path/somewhere/file2
foo Not found
bar Not found
No loops necessary.
Whats wrong with using a script. I hope this will do.
#!/bin/bash -f
for i in $#
do
var=`find $HOME -name $i`
if [ -z "$var"]
then
var="File not found"
fi
echo $var
done
You can use the shell builtin 'test' to test the existence of a file. There is also an alternative syntax using square brackets:
if [ -f $a ]; then # Don't forget the semicolon.
echo $a
else
echo 'Not Found'
fi
Here is one way - create a list of all the files to grep against. If your implementation supports
grep -q otherwise use grep [pattern] 2&>1 >/dev/null....
find $HOME -type f |
while read fname
do
echo "$(basename $fname) $fname"
done > /tmp/chk.lis
while read fname
do
grep -q "^$fname" /tmp/chk.lis
[ $? -eq 0 ] && echo "$fname found" || echo "$fname not found"
done < /tmp/chk.lis
All of this is needed because POSIX find does not return an error when a file is not found
perl -nlE'say-f$_?$_:"not found: $_"' file

best way to find top-level directory for path in bash

I need a command that will return the top level base directory for a specified path in bash.
I have an approach that works, but seems ugly:
echo "/go/src/github.myco.com/viper-ace/psn-router" | cut -d "/" -f 2 | xargs printf "/%s"
It seems there is a better way, however all the alternatives I've seen seem worse.
Thanks for any suggestions!
One option is using awk:
echo "/go/src/github.myco.com/viper-ace/psn-router" |
awk -F/ '{print FS $2}'
/go
As a native-bash approach forking no subshells and invoking no other programs (thus, written to minimize overhead), which works correctly in corner cases including directories with newlines:
topdir() {
local re='^(/+[^/]+)'
[[ $1 =~ $re ]] && printf '%s\n' "${BASH_REMATCH[1]}"
}
Like most other solutions here, invocation will then look something like outvar=$(topdir "$path").
To minimize overhead even further, you could pass in the destination variable name rather than capturing stdout:
topdir() {
local re='^(/+[^/]+)'
[[ $1 =~ $re ]] && printf -v "$2" '%s' "${BASH_REMATCH[1]}"
}
...used as: topdir "$path" outvar, after which "$outvar" will expand to the result.
not sure better but with sed
$ echo "/go/src/github.myco.com/viper-ace/psn-router" | sed -E 's_(/[^/]+).*_\1_'
/go
Here's a sed possibility. Still ugly. Handles things like ////////home/path/to/dir. Still blows up on newlines.
$ echo "////home/path/to/dir" | sed 's!/*\([^/]*\).*!\1!g'
/home
Newlines breaking it:
$ cd 'testing '$'\n''this'
$ pwd
/home/path/testing
this
$ pwd | sed 's!/*\([^/]*\).*!/\1!g'
/home
/this
If you know your directories will be rather normally named, your and anubhava's solutions certainly seem to be more readable.
This is bash, sed and tr in a function :
#!/bin/bash
function topdir(){
dir=$( echo "$1" | tr '\n' '_' )
echo "$dir" | sed -e 's#^\(/[^/]*\)\(.*\)$#\1#g'
}
topdir '/go/src/github.com/somedude/someapp'
topdir '/home/somedude'
topdir '/with spaces/more here/app.js'
topdir '/with newline'$'\n''before/somedir/somefile.txt'
Regards!

Resources