Bash: wildcard in argument expands to a filename [duplicate] - regex
This question already has answers here:
When to wrap quotes around a shell variable?
(5 answers)
I just assigned a variable, but echo $variable shows something else
(7 answers)
Closed 4 years ago.
This is my script:
#!/bin/bash
set -x
arguments="some explanation"
if [[ $1 == -f ]]; then
exiftool '-FileName<DateTimeOriginal' -d "%Y-%m-%d %H,%M,%S.%%e" "$2"
elif [[ $1 == -d ]]; then
exiftool -d %Y-%m "-directory<datetimeoriginal" "$2"
elif [[ $1 == -fd ]]; then
exiftool '-FileName<DateTimeOriginal' -d "%Y-%m-%d %H,%M,%S.%%e" "$2"
exiftool -d %Y-%m "-directory<datetimeoriginal" "$2"
elif [[ $1 == -p ]]; then
exiftool '-FileName<DateTimeOriginal' -d "%Y-%m-%d.%%e" "$2"
else
echo -e $arguments
fi
set +x
If I run exifrename -f . it renames all files in the current folder. But let's say I have the following 3 files:
IMAG01234.jpg
IMAG01235.jpg
Ralph at home.jpg
and with them I run `exifrename -f IMAG*. It only renames one IMAG file.
When I debug this script, I see this:
+ [[ -d == -f ]]
+ [[ -d == -d ]]
+ exiftool -d %Y-%m '-directory<datetimeoriginal' IMAG01235.jpg
What can I do make the last line say IMAG* and not IMAG01235?
When you are doing IMAG*, then the bash shell does globbing and expands IMAG* to 2 files and passes them as arguments to your script. You need to iterate through all the command line arguments:
Example:
#!/bin/bash
option="$1" # this contains -f, -d, or something.
shift 1
for filename in "$#"; do
ls -al "$filename" # Just an example. But you get the point.
done
In your case, you could do the following assuming, that there would be always be one option and followed by list of files.
option="$1"
shift 1
for filename in "$#"; do
if [[ "$option" == '-f' ]]; then
exiftool '-FileName<DateTimeOriginal' -d "%Y-%m-%d %H,%M,%S.%%e" "$filename"
elif [[ "$option" == '-d' ]]; then
exiftool -d %Y-%m "-directory<datetimeoriginal" "$filename"
elif [[ "$option" == '-fd' ]]; then
exiftool '-FileName<DateTimeOriginal' -d "%Y-%m-%d %H,%M,%S.%%e" "$filename"
exiftool -d %Y-%m "-directory<datetimeoriginal" "$filename"
elif [[ "$option" == '-p' ]]; then
exiftool '-FileName<DateTimeOriginal' -d "%Y-%m-%d.%%e" "$filename"
else
echo -e $arguments
fi
done
Note: If you comfortable with bash scripting, it is more readable to do with case/esac instead of bunch of if/else.
Related
How to structure a compound conditional with several tests (at least 1 of which is regex)
I searched for this but haven't found an answer to this particular situation. I'm familiar with file tests in shells and with using the [[ ]] syntax to perform regex matching. Is there a way to combine these two operations in a compound conditional that doesn't require multiple nested ifs? So far I've tried the following (...and other much crazier variations): if [ -e ~/.profile -a $0 =~ bash ]; then echo yes ; fi if [ -e ~/.profile -a ( $0 =~ bash ) ]; then echo yes ; fi if [ -e ~/.profile -a [ $0 =~ bash ] ]; then echo yes ; fi if [[ -e ~/.profile -a $0 =~ bash ]]; then echo yes ; fi if [[ ( -e ~/.profile ) -a ( $0 =~ bash ) ]]; then echo yes ; fi if [ -e ~/.profile -a $0 =~ bash ]; then echo yes; fi if [ -e ~/.profile -a $( [ $0 =~ bash ] ) ]; then echo yes; fi if [ -e ~/.profile -a [[ $0 =~ bash ]] ]; then echo yes; fi if [ -e ~/.profile -a $([[ $0 =~ bash ]]) ]; then echo yes; fi
-a is treated as an AND when using single brackets, eg: $ [ 3 -gt 1 -a 2 -lt 3 ] && echo 'true' true For double brackets you want to use &&, eg: $ [[ 3 -gt 1 && 2 -lt 3 ]] && echo 'true' true Alternatively you can && to separate tests regardless of whether you're using single or double brackets, eg: $ [ 3 -gt 1 ] && [ 2 -lt 3 ] && echo 'true' true $ [[ 3 -gt 1 ]] && [[ 2 -lt 3 ]] && echo 'true' true $ [ 3 -gt 1 ] && [[ 2 -lt 3 ]] && echo 'true' true NOTE: same rules apply for -o vs || (aka OR)
Apparently, when you want to represent a LOGICAL AND between these two statements, you must use && instead of -a (which the shell interprets as "does this file exist" file test in double brackets). Also, for the regex to work, the statement must be within [[ ]]. What was unknown to me at the time is that even though -a changes its meaning in double brackets, the -e -w -r and other file tests don't change their functionality (e.g. it's the same for single or double brackets). if [[ -w ~/.bash_profile && $0 =~ bash ]]; then ( echo 1 ; echo 2 ) >> .bash_profile elif [[ -w ~/.profile && <someothercondition> ]]; then ( echo 3 echo 4 echo 5 ) >> .profile fi
Use SED to replace curlybrace and add insert a character
I have a ".csv" file that is generated by a BASH script. Within that script I have a sed statement to make some changes in the file the script output just 1 line earlier. I'm trying to sed the file and remove/replace a few encoding characters. I'm trying to replace '{' in the file, wherever it occurs, with a zero '0'. Additionally, I need to prepend the match with a plus '+'. Here is the most recent try (of hundreds of previous tries): sed -r 's/^(.*)([\{])(.*)$/\1\+0\3/g' -i "$FILENAME" Here is a sample of my data: 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,F,BI,,,D,7391420002 Frustratingly, it only seems to match the first line and then quit, despite the global flag '/g' being on: 4240880002,9000413542,001,000000000000000+0,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,000000000000000{,000000000000011P,000000000000000{,000000000000011P,A,2006060000,,,F,BI,,,D,7391420002 Here is how I am trying to format it: (I included my next character replacement P=7): 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,F,BI,,,D,7391420002 My brain has been rendered to hamburger meat over this! :( I sincerely appreciate your help! UPDATE This is conversion chart I'm working from: Character Digit Sign { 0 + A 1 + B 2 + C 3 + D 4 + E 5 + F 6 + G 7 + H 8 + I 9 + } 0 - J 1 - K 2 - L 3 - M 4 - N 5 - O 6 - P 7 - Q 8 - R 9 -
Your sedcommand was getting close. Two things to change: Do not match beginning and end-of-line. Match with characters that are not a ,. You will get sed -r 's/,([^,]*)\{([^,])*/,+\10\2/g; s/,([^,]*)P([^,]*)/,-\17\2/g' "$FILENAME"
Good grief, just use awk: $ cat tst.awk BEGIN { mkmap("{ A B C D E F G H I","+") mkmap("} J K L M N O P Q R","-") FS=OFS="," } { for (i=1; i<=NF; i++) { for (char in map) { num = map[char] if ( sub(char,num,$i) ) { $i = pfx[char] $i } } } print } function mkmap(list,sign, char,tmp,num) { split(list,tmp,/ /) for (num in tmp) { char = tmp[num] map[char] = num-1 pfx[char] = sign } } . $ awk -f tst.awk file 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+1,++29,,,+3,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+1,++29,,,+3,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+1,++29,,,+3,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+1,++29,,,+3,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+1,++29,,,+3,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+1,++29,,,+3,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+1,++29,,,+3,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,+1,2006060000,,,+6,++29,,,+4,7391420002 You don't say what to do if 2 characters appear in a field so idk if what I'm doing above is what you want or not but that code should be trivial enough to modify to do whatever it is you want with that and to add whatever other transformations you need.
This might work for you (GNU sed): sed 's/[^,]*[{A-I]\+/+&/g;s/[^,]*[}J-R]\+/-&/g;y/{ABCDEFGHI}JKLMNOPQR/01234567890123456789/' file First insert either + or - infront of fields containing the translation encodings. Then translate the encodings.
after reading it again, here is another solution with awk $ awk 'BEGIN {FS=OFS=","} {for(i=1;i<=NF;i++) {if(gsub(/{/,0,$i)) $i="+"$i; if(gsub(/P/,7,$i)) $i="-"$i} }1' file 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,A,BI,,,C,7639840002 4240880002,9000413542,001,+0000000000000000,-0000000000000117,+0000000000000000,-0000000000000117,A,2006060000,,,F,BI,,,D,7391420002
take +0 -0 +1 -1 out of your conversion chart, it should work.
I really appreciate all the help! You all helped me get very close. In the end, this is what ended up solving the issues. THANK YOU! #!/bin/bash function FixEncodedStrings(){ if [[ "$1" =~ ([0-9]{3,})\{([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})\{([0-9]{1,})?/+\10\2/g' elif [[ "$1" =~ ([0-9]{3,})A([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})A([0-9]{1,})?/+\11\2/g' elif [[ "$1" =~ ([0-9]{3,})B([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})B([0-9]{1,})?/+\12\2/g' elif [[ "$1" =~ ([0-9]{3,})C([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})C([0-9]{1,})?/+\13\2/g' elif [[ "$1" =~ ([0-9]{3,})D([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})D([0-9]{1,})?/+\14\2/g' elif [[ "$1" =~ ([0-9]{3,})E([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})E([0-9]{1,})?/+\15\2/g' elif [[ "$1" =~ ([0-9]{3,})F([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})F([0-9]{1,})?/+\16\2/g' elif [[ "$1" =~ ([0-9]{3,})G([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})G([0-9]{1,})?/+\17\2/g' elif [[ "$1" =~ ([0-9]{3,})H([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})H([0-9]{1,})?/+\18\2/g' elif [[ "$1" =~ ([0-9]{3,})I([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})I([0-9]{1,})?/+\19\2/g' elif [[ "$1" =~ ([0-9]{3,})\}([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})\}([0-9]{1,})?/-\10\2/g' elif [[ "$1" =~ ([0-9]{3,})J([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})J([0-9]{1,})?/-\11\2/g' elif [[ "$1" =~ ([0-9]{3,})K([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})K([0-9]{1,})?/-\12\2/g' elif [[ "$1" =~ ([0-9]{3,})L([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})L([0-9]{1,})?/-\13\2/g' elif [[ "$1" =~ ([0-9]{3,})M([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})M([0-9]{1,})?/-\14\2/g' elif [[ "$1" =~ ([0-9]{3,})N([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})N([0-9]{1,})?/-\15\2/g' elif [[ "$1" =~ ([0-9]{3,})O([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})O([0-9]{1,})?/-\16\2/g' elif [[ "$1" =~ ([0-9]{3,})P([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})P([0-9]{1,})?/-\17\2/g' elif [[ "$1" =~ ([0-9]{3,})Q([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})Q([0-9]{1,})?/-\18\2/g' elif [[ "$1" =~ ([0-9]{3,})R([0-9]{1,})? ]] then echo "$1" | sed -r 's/([0-9]{3,})R([0-9]{1,})?/-\19\2/g' fi }
Renaming directories based on a pattern in Bash
I have a Bash script that works well for just renaming directories that match a criteria. for name in *\[*\]\ -\ *; do if [[ -d "$name" ]] && [[ ! -e "${name#* - }" ]]; then mv "$name" "${name#* - }" fi done Currently if the directory looks like: user1 [files.sentfrom.com] - Directory-Subject It renames the directory and only the directory to look like Directory-Subject (this could have different type of text) How can I change the script / search criteria to now search for www.ibm.com - Directory-Subject and rename the directory and only the directory to Directory-Subject
You could write your code this way so that it covers both the cases: for dir in *\ -\ *; do [[ -d "$dir" ]] || continue # skip if not a directory sub="${dir#* - }" if [[ ! -e "$sub" ]]; then mv "$dir" "$sub" fi done Before running the script: $ ls -1d */ user1 [files.sentfrom.com] - Directory-Subject/ www.ibm.com - Directory-Subject After: $ ls -1d */ Directory-Subject/ www.ibm.com - Directory-Subject/ # didn't move because directory existed already
A simple answer would be to change *\[*\]\ -\ * to *\ -\ * for name in *\ -\ *; do if [[ -d "$name" ]] && [[ ! -e "${name#* - }" ]]; then mv "$name" "${name#* - }" fi done For more information, please read glob and wildcards
Splitting all txt files in a folder into smaller files based on a regular expression using bash
I have a folder containing large text files. Each file is a collection of 1000 files separated by [[ file name ]]. I want to split the files and make 1000 files out of them and put them in a new folder. Is there a way in bash to do it? Any other fast method will also do. for f in $(find . -name '*.txt') do mkdir $f mv cd $f awk '/[[.*]]/{g++} { print $0 > g".txt"}' $f cd .. done
You are trying to create a folder with the same name of the already existing file. for f in $(find . -name '*.txt') do mkdir $f Here, "find" will list the files in the current path, and for each of these files you will try to create a directory with exactly the same name. One way of doing it would be first creating a temporary folder: for f in $(find . -name '*.txt') do mkdir temporary # create a temporary folder mv $f temporary # move the file into the folder mv temporary $f # rename the temporary folder to the name of the file cd $f # enter the folder and go on.... awk '/[[.*]]/{g++} { print $0 > g".txt"}' $f cd .. done Note that all your folders will have the ".txt" extension. If you don't want that, you can cut it out before creating the folder; that way, you won't need the temporary folder, because the folder you're trying to create has a different name from the .txt file. Example: for f in $(find . -name '*.txt' | rev | cut -b 5- | rev)
Although not awk and written and written by a drunk person, not guaranteed to work. import re import sys def main(): pattern = re.compile(r'\[\[(.+)]]') with open (sys.argv[1]) as f: for line in f: m = re.search(pattern, line) if m: try: with open(fname, 'w+') as g: g.writelines(lines) except NameError: pass fname = m.group(1) lines = [] else: lines.append(line) with open(fname, 'w+') as g: g.writelines(lines) if __name__ == '__main__': main()
Write a bash script. Here, I've done it for you. Notice the structure and features of this script: explain what it does in a usage() function, which is used for the -h option. provide a set of standard options: -h, -n, -v. use getopts to do option processing do lots of error checking on the arguments be careful about filename parsing (notice that blanks surrounding the file names are ignored. hide details within functions. Notice the 'talk', 'qtalk', 'nvtalk' functions? Those are from a bash library I've built to make this kind of scripting easy to do. explain what is going on to the user if in $verbose mode. provide the user the ability to see what would be done without actually doing it (the -n option, for $norun mode). never run commands directly. but use the run function, which pays attention to the $norun, $verbose, and $quiet variables. I'm not just fishing for you, but teaching you how to fish. Good luck with your next bash script. Alan S. #!/bin/bash # split-collections IN-FOLDER OUT-FOLDER PROG="${0##*/}" usage() { cat 1>&2 <<EOF usage: $PROG [OPTIONS] IN-FOLDER OUT-FOLDER This script splits a collection of files within IN-FOLDER into separate, named files into the given OUT-FOLDER. The created file names are obtained from formatted text headers within the input files. The format of each input file is a set of HEADER and BODY pairs, where each HEADER is a text line formatted as: [[input-filename1]] text line 1 text line 2 ... [[input-filename2]] text line 1 text line 2 ... Normal processing will show the filenames being read, and file names being created. Use the -v (verbose) option to show the number of text lines being written to each created file. Use -v twice to show the actual lines of text being written. Use the -n option to show what would be done, without actually doing it. Options -h Show this help -n Dry run -- do NOT create any files or make any changes -o Overwrite existing output files. -v Be verbose EOF exit } talk() { echo 1>&2 "$#" ; } chat() { [[ -n "$norun$verbose" ]] && talk "$#" ; } nvtalk() { [[ -n "$verbose" ]] || talk "$#" ; } qtalk() { [[ -n "$quiet" ]] || talk "$#" ; } nrtalk() { talk "${norun:+(norun) }$#" ; } error() { local code=2 case "$1" in [0-9]*) code=$1 ; shift ;; esac echo 1>&2 "$#" exit $code } talkf() { printf 1>&2 "$#" ; } chatf() { [[ -n "$norun$verbose" ]] && talkf "$#" ; } nvtalkf() { [[ -n "$verbose" ]] || talkf "$#" ; } qtalkf() { [[ -n "$quiet" ]] || talkf "$#" ; } nrtalkf() { talkf "${norun:+(norun) }$#" ; } errorf() { local code=2 case "$1" in [0-9]*) code=$1 ; shift ;; esac printf 1>&2 "$#" exit $code } # run COMMAND ARGS ... qrun() { ( quiet=1 run "$#" ) } run() { if [[ -n "$norun" ]]; then if [[ -z "$quiet" ]]; then nrtalk "$#" fi else if [[ -n "$verbose" ]]; then talk ">> $#" fi if ! eval "$#" ; then local code=$? return $code fi fi return 0 } show_line() { talkf "%s:%d: %s\n" "$in_file" "$lines_in" "$line" } # given an input filename, read it and create # the output files as indicated by the contents # of the text in the file split_collection() { in_file="$1" out_file= lines_in=0 lines_out=0 skipping= while read line ; do : $(( lines_in++ )) [[ $verbose_count > 1 ]] && show_line # if a line with the format of "[[foo]]" occurs, # close the current output file, and open a new # output file called "foo" if [[ "$line" =~ ^\[\[[[:blank:]]*([^ ]+.*[^ ]|[^ ])[[:blank:]]*\]\][[:blank:]]*$ ]] ; then new_file="${BASH_REMATCH[1]}" # close out the current file, if any if [[ "$out_file" ]]; then nrtalkf "%d lines written to %s\n" $lines_out "$out_file" fi # check the filename for bogosities case "$new_file" in *..*|*/*) [[ $verbose_count < 2 ]] && show_line error "Badly formatted filename" ;; esac out_file="$out_folder/$new_file" if [[ -e "$out_file" ]]; then if [[ -n "$overwrite" ]]; then nrtalk "Overwriting existing '$out_file'" qrun "cat /dev/null >'$out_file'" else error "$out_file already exists." fi else nrtalk "Creating new output file: '$out_file' ..." qrun "touch '$out_file'" fi lines_out=0 elif [[ -z "$out_file" ]]; then # apparently, there are text lines before the filename # header; ignore them (out loud) if [[ ! "$skipping" ]]; then talk "Text preceding first filename ignored.." skipping=1 fi else # next line of input for the file qrun "echo \"$line\" >>'$out_file'" : $(( lines_out++ )) fi done } norun= verbose= verbose_count=0 overwrite= quiet= while getopts 'hnoqv' opt ; do case "$opt" in h) usage ;; n) norun=1 ;; o) overwrite=1 ;; q) quiet=1 ;; v) verbose=1 ; : $(( verbose_count++ )) ;; esac done shift $(( OPTIND - 1 )) in_folder="${1:?Missing IN-FOLDER; see $PROG -h for details}" out_folder="${2:?Missing OUT-FOLDER; see $PROG -h for details}" # validate the input and output folders # # It might be reasonable to create the output folder for the # user, but that's left as an exercise for the user. in_folder="${in_folder%/}" # remove trailing slash, if any out_folder="${out_folder%/}" [[ -e "$in_folder" ]] || error "$in_folder does not exist" [[ -d "$in_folder" ]] || error "$in_folder is not a directory." [[ -e "$out_folder" ]] || error "$out_folder does not exist." [[ -d "$out_folder" ]] || error "$out_folder is not a directory." for collection in $in_folder/* ; do talk "Reading $collection .." split_collection "$collection" <$collection done exit
How to simplify this bash shell code
This is my code if grep -q $lines scanHistory;then echo -n '' else if grep -q $lines waiting;then echo -n '' else Download $lines echo "---$lines was download successfully" fi fi my purpoes is if $line can't be found in both scanHistory and waiting, then run Download. I had try to make This code more simplily, and write if as if grep -qv $lines scanHistory && grep -qv $lines waiting; then .... but a failured....
try: if ! grep -q $lines scanHistory && ! grep -q $lines waiting; then ... The initial attempt using grep -v failed because grep -v succeeds if any line of the input does not match the pattern.
Maybe you want if ! ( grep -q $lines scanHistory || grep -q $lines waiting ) ; then .... The problem is that -v doesn't work the way you think it should When you grep nonexistant file, you get 1, it didn't find it, but when you grep -v nonexistant file the return code is 0 because all the other lines in file DID negative-match 'nonexistant. I hope this helps.
grep -q -e "$lines" scanHistory -e "$lines" waiting if [ $? -ne 0 ] # Check if the above command is a success or not, if not run downlaod. then <run_Download> fi
Using bash short circuiting operators && and ||: grep -q $lines scanHistory || grep -q $lines waiting || Download $lines && echo "---$lines was download successfully" It can be put on a single line, as bellow, but the above is more readable: grep -q $lines scanHistory || grep -q $lines waiting || Download $lines && echo "---$lines was download successfully"