UNIX: error when I try to use array - regex

I have this code and when I try it in FreeBSD it shows me a lot of errors... how can I fix it? I check directories, if it match with variable IGN. NAME_d should be an array.
max_d=$(find "${DIR}" -type d | wc -l)
for i in `seq 1 $max_d`
do
check_d=$(find "${DIR}" -type d | head -n "${i}" | tail -n -1 | tr '\/' '\n' | egrep -n "${IGN}")
if [ ! -z "$check_d" ]; then
NAME_d+=$i"d "
fi
done
directory_d=${NAME_d[*]}
sedCmds_d=${directory_d// /;}

Arrays are a bashism not supported by the Almquist shell, the default bourne style shell on FreeBSD (i.e. /bin/sh). An advantage of the shell is that most scripts run about 3 times faster.
If you want to use bashisms, use bash to execute your script. E.g. call it bash dirstat.sh or change the shebang.
This is the correct one for FreeBSD.
#!/usr/local/bin/bash
This is the portable version but requires PATH to be set:
#!/usr/bin/env bash
You also might have to install bash first: pkg add bash

Not sure if it will solve it, but if you're using bash, you should initiate NAME_d as an array
NAME_d=()
and then adding to the array you should also use parens, e.g.
NAME_d+=("${i}d ")

Related

How to properly run find | parallel with grep + escape characters?

I have approximately 1500 2GB files in a folder and would like to extract lines from them based on a regex. I tried:
find . -regex "filename pattern" -exec grep -P "pattern1\t|pattern2\t|pattern3\t|...|patternN\t" {} +
which works perfectly, but is pretty slow. I then read about running grep with GNU parallel, but couldn't figure out how to properly use it. Here's what I tried:
find . -regex "filename pattern" | parallel grep -P "pattern1\t|pattern2\t|pattern3\t|...|patternN\t" {}
along with a few variations of this command. However, I get in return:
/bin/bash: pattern1t: command not found
/bin/bash: pattern3t: command not found
/bin/bash: pattern2t: command not found
...
It seems the problem lies with the \t I use to ensure I match an entire string in a column of a TSV file. The grep command without parallel works perfectly with this regex.
How can I use escape characters in the grep regex with parallel?
As #Mark Setchell pointed out, I missed the "--quote" argument! This solution works:
find . -regex "filename pattern" -print0 | parallel -0 --quote grep -P "pattern1\t|pattern2\t|pattern3\t|...|patternN\t"

Passing Multiple Files in SED Command: Log Extract

I am trying to extract logs from my application within specific time-stamps. So i wrote the following script
a= echo $1 | sed 's/\//\\\//g';
b= echo $2 | sed 's/\//\\\//g';
sed -n "/$a/,/$b/p" $3;
Here $1 and $2 are the timestamps within which i want the logs and $3 is the file from where i want it.
This script works perfect if i pass a single file. But if i multiple files or a directory as parameters it does not give any output.
This is how i am executing the script
extract.sh '6/30/14 9:03' '6/30/14 9:05' abc_*/SysOut.log
Can SED work with multiple files or the issue is with UNIX with its limitation in passing files as parameters
Any suggesstion of help in this regard?
Your sed command should be
sed -n "/$a/,/$b/p" -- "${#:3}"
Note if you're not using Bash, you can shift those arguments first before running sed:
shift 2
sed -n "/$a/,/$b/p" -- "$#"

pattern matching while using ls command in bash script

In a sh script, I am trying to loop over all files that match the following pattern
abc.123 basically abc. followed by only numbers, number following . can be of any length.
Using
$ shopt -s extglob
$ ls abc.+([0-9])
does the job but on terminal and not through the script. How can I get only files that match the pattern?
if I understood you right, the pattern could be translated into regex:
^abc\.[0-9]+$
so you could
keep using ls and grep the output. for example:
ls *.*|xargs -n1|grep -E '^abc\.[0-9]+$'
or use find
find has an option -regex
If you're using sh and not bash, and presumably you also want to be POSIX compliant, you can use:
for f in ./*
do
echo "$f" | grep -Eq '^\./abc.[0-9]+$' && continue
echo "Something with $f here"
done
It will work fine with filenames with spaces, quotes and such, but may match some filenames with line feeds in them that it shouldn't.
If you tagged your question bash because you're using bash, then just use extglob like you described.

Pass a regular expression as a parameter to a shell script

How to pass a regular expression as a parameter to a shell script?
I need to write a shell script, which will take parameters and give them to unix commands. And I'd like to use regular expressions there. Is this possible at all?
Or reformulation - how to write the script equivalent to "cp" command, using only this command?
I'm trying to make a file "mycp"
#!/bin/bash -fx
cp $2 $1
and call it by
mycp myDir "*sh"
and want it to do the same as "cp *sh myDir".
But resulting bash interpretation is:
+ cp '*sh' myDir
cp: *sh: No such file or directory
Revised question
I'm trying to make a file "mycp"
#!/bin/bash -fx
cp $2 $1
and call it by
mycp myDir "*sh"
In that case, you still need eval, but you'd write:
#!/bin/bash -x
eval cp "$2" "$1"
You're running into problems because you have specified the -f option. man bash says (in part):
After word splitting, unless the -f option has been set, bash scans each word for the characters *, ?, and [.
Remove the f from the 'shebang' (first) line of the script.
Original question
Given that you want mycp "*sh*" aa to do shell expansion on the argument, you'll probably end up using eval in your script:
eval cp "$#"
However, the use of eval is dangerous; it can lead to unexpected side-effects. The use of "$#" is important; it preserves the number of arguments and spaces in them. Unfortunately, using eval then undoes that, but we can't have everything — or not easily.
For quite a long time (say 1987* to 1999), I used this script as a cover for cp:
: "#(#)$Id: cp.sh,v 1.3 1997/06/02 21:45:00 johnl Exp $"
#
# Alternative copy command
case $# in
0) /bin/cp ;;
1) /bin/cp $1 . ;;
2) /bin/cp "$#" ;;
*) if [ -d `la "$#"` ]
then /bin/cp "$#"
else /bin/cp "$#" .
fi;;
esac
It uses a very simple C program called la (for 'last argument') to get the last argument and checks whether the given last argument is a directory. More than 99% of the time, if I typed (by accident) 'cp /some/where/sh' rather than cp /some/where/*sh* ., the second was what I meant, and the script fixed things. I haven't used it for quite some time; it may have been in the last millennium, but was probably sometime earlier in this one that I gave up using it.
* Although the version string says '1997', the code is identical to the 1987 version. Version 1.1 and 1.2 were under SCCS and used different SCCS ID strings; the conversion to RCS made them identical. Version 1.3 reinstated the #(#) identifier string used by the SCCS what command to the RCS version handling. So, the script is ancient — 1987, really.
Try this: eval cp $1 $2
Bash reference manual: eval
If all you want to do is specify the directory first, look at the -t option to GNU cp:
alias mycp='cp -t'
mycp mydir *.sh
Otherwise:
mycp() {
local dir=$1
shift
cp "$#" "$dir"
}
mycp mydir *.sh
Either way, let the shell expand the wildcards and avoid the use of eval
(note, *.sh is not a regular expression, it's a shell "pattern", often referred to as a "glob pattern")

grep with regexp: whitespace doesn't match unless I add an assertion

GNU grep 2.5.4 on bash 4.1.5(1) on Ubuntu 10.04
This matches
$ echo "this is a line" | grep 'a[[:space:]]\+line'
this is a line
But this doesn't
$ echo "this is a line" | grep 'a\s\+line'
But this matches too
$ echo "this is a line" | grep 'a\s\+\bline'
this is a line
I don't understand why #2 does not match (whereas # 1 does) and #3 also shows a match. Whats the difference here?
Take a look at your grep manpage. Perl added a lot of regular expression extensions that weren't in the original specification. However, because they proved so useful, many programs adopted them.
Unfortunately, grep is sometimes stuck in the past because you want to make sure your grep command remains compatible with older versions of grep.
Some systems have egrep with some extensions. Others allow you to use grep -E to get them. Still others have a grep -P that allows you to use Perl extensions. I believe Linux systems' grep command can use the -P extension which is not available in most Unix systems unless someone has replaced the grep with the GNU version. Newer versions of Mac OS X also support the -P switch, but not older versions.
grep doesn't support the complete set of regular expressions, so try using -P to enable perl regular expressions. You don't need to escape the + i.e.
echo "this is a line" | grep -P 'a\s+line'