0

I have an exe which takes 2 parameters both are csv as below splitline.exe /dir/file1.csv /dir1/file2.csv, this basically splits the lines in the input file to 2 lines in the output file.So,I wrote a shell script to execute this exe. the directory is fixed,but the filename can differ, both filename in src directory and destination directory should be same.I am running it on windows environment.It is having MKS installed,so unix and shell script also can be executed. Below is the code snippet which I wrote:

#!/bin/sh
 srcdir='D:/srcdir/srcdir1/'

 destdir='D:/destdir/destdir1/'

 extension='csv'

srcfile='${srcdir}/*.csv'

if [[-f ${srcfile} in ${srcdir}]]
  then
   cSplit.exe "${srcdir}/{srcfile}.${extension}" "${destdir}/${srcfile}.${extension}"
    mv "${srcfile}" "${srcdir}/old"
else
    echo "no file"
fi

output: [[-f : splitty.sh 21 not found Its giving output as "no file" Please correct my mistake,as I am new to shell script

Aaron
  • 24,009
  • 2
  • 33
  • 57
  • "Please correct my mistake" > please describe the problem you're encountering. Or maybe the code works and you'd just like to improve it where possible? If so, you should post on the [CodeReview SE](https://codereview.stackexchange.com/). You should also tell us on which environment you plan to execute your code, as mixing windows exe and paths with shell scripts is unusual and has specificities which depend on the environment your run the script on. – Aaron Jan 24 '19 at 14:10
  • if I put a space it is giving error as "Expression syntax error" – Raghav manchale Jan 24 '19 at 14:15
  • You need a space between `[[` and whatever follows; also between `]]` and whatever precedes them. – mustaccio Jan 24 '19 at 14:15
  • 1
    Your immediate error is due to the lack of space between `[[` and `-f`, but the whole condition doesn't make sense. You will probably want to first iterate over the list of files the `srcfile` glob matches with `for file in $srcfile` then check if those actually are files with `if [[ -f "$file" ]]; then ...` – Aaron Jan 24 '19 at 14:16
  • I'll also recommend using [shellcheck](https://www.shellcheck.net/) which would have caught the missing space and once fixed said it couldn't parse the condition. I don't know how well it works with shell scripts running under windows though. – Aaron Jan 24 '19 at 14:20
  • I'm finding difficulty in fetching the .csv file from srcdir and also putting the ouput.csv in destination dir – Raghav manchale Jan 24 '19 at 14:48
  • Note the [mcve] definition in the Help Center -- we expect each question to revolve around *exactly one* error, with everything not necessary to cause or test for that error removed. So why `[[-f "$file" in $srcdir]]` doesn't work is *one error*; if it's the error you're asking about, everything else should be removed. – Charles Duffy Jan 24 '19 at 16:11

2 Answers2

1

How about this template:

#!/bin/bash
src="D:/srcdir/srcdir1"               # no '/' at the end of dirname
dst="D:/destdir/destdir1"
cd "$src" || exit                     # do nothing if $src is not a directory

for f in *.csv; do
  if [[ "$f" = '*.csv' ]]; then
    echo "no files"
    break
  fi
  if [[ -f "$f" ]]; then
    echo cSplit.exe "$f" "$dst/$f"    # use 'echo' for testing
    echo mv "$f" "$src/old/."         #   aka dry run
  fi
done

Note 1: If you are using Windows, then using / is OK in bash; but the command cSplit.exe may not accept / as directory delimiter. I am not using Windows, so I cannot check that.

Note 2: I do not really know Windows, so I tried NOT to use other commands like basename, or find, etc. As for drive name D: please check. Maybe it is mapped to /mnt/d or something.

Note 3: I've fixed the script based on Charles comments.

Bach Lien
  • 1,030
  • 6
  • 7
  • I tried the above,but its not going inside else loop,its giving as "no files" means its checking if loop and exiting.. But .csv file is present inside the directory srcdir1 – Raghav manchale Jan 24 '19 at 15:51
  • @raghav: oh... i do not have windows; but that "D:/..." may not work. Please check the what the drive 'd:' is mapped to. – Bach Lien Jan 24 '19 at 15:55
  • Umm. `files=*.csv` doesn't expand the glob **at all**; it remains unexpanded until the use of `for f in $files`. To do it right, you'd make it an array: `files=( *.csv )`; `if [[ ${files[0]} = '*csv' ]]`, or just `shopt -s nullglob` and `files=( *.csv )`, after which you can test `if (( ${#files[@]} == 0 ))` and iterate over `for f in "${files[@]}"`. – Charles Duffy Jan 24 '19 at 16:07
  • As proof of the above assertion, consider the following: `cd /tmp && { rm -f -- *.csv; touch exists.csv; files=*.csv; echo "$files"; }` -- you'll see that it echos `*.csv`, even though `exists.csv` was created. – Charles Duffy Jan 24 '19 at 16:09
  • Also, I'd consider `(( ${#files[@]} == 0 )) && { echo "No files exist" >&2; exit; }` -- no reason to put everything else in an `else` block when you can just abort execution in the error case. – Charles Duffy Jan 24 '19 at 16:10
  • @Charles: hey, if you write everything in ONE line, then of course 'files' will not contain exists.csv. – Bach Lien Jan 24 '19 at 16:12
  • @BachLien, huh? The distinction between semicolons and newlines as linebreaks has no impact whatsoever on semantics. Globs are expanded when the simple command containing them is executed, not before. – Charles Duffy Jan 24 '19 at 16:13
  • @BachLien, ...you can test that too: `cd /tmp && { rm -f -- *.csv; touch exists.csv; echo *.csv; }` shows `exists.csv` as output; it's **specifically** the assignment (`files=*.csv`) that doesn't perform expansion. – Charles Duffy Jan 24 '19 at 16:13
  • @Charles: in `cd /tmp && { rm -f -- *.csv; touch exists.csv; files=*.csv; echo "$files"; }`, the `*.csv` is parsed by `bash` before it excutes `touch`. – Bach Lien Jan 24 '19 at 16:14
  • @BachLien, that is untrue (well, "parsed" is true, but the implied "expanded" is not). As I told you, globs are expanded as part of the processing of each simple command. Moreover, I gave you a second test you could execute to prove to yourself that it's untrue. – Charles Duffy Jan 24 '19 at 16:14
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/187273/discussion-between-charles-duffy-and-bach-lien). – Charles Duffy Jan 24 '19 at 16:16
  • @CharlesDuffy: OK you are right. But I've tested: `touch {1,2,3}.csv;files=*.csv;echo $files` and the result is correct. – Bach Lien Jan 24 '19 at 16:21
  • It's correct for that trivial case, but it's not as correct for some less-trivial ones. Since we're building a teaching resource here, better to showcase robust practices, and I thank you for making the edits you have. – Charles Duffy Jan 24 '19 at 16:33
  • the problem in all this is ,it taking the filename as *.csv only, so the exe is not working.The exe requires exact filename. so how to make that happen? – Raghav manchale Jan 25 '19 at 02:49
  • Finally,I'm able to track the problem and resolve it. #!/bin/sh src="D:/Dir1/Dir" dst="D:/Dir2/Dir3" srcfile1=$(find ${src} -name *.csv) ext="csv" STARTTIME=`date '+%Y%m%d.%H%M%S'` cSplittingLines.exe $srcfile1 $dst/out_$STARTTIME.$ext mv $srcfile1 $src/old – Raghav manchale Jan 25 '19 at 09:56
0

I would use something along those lines :

#!/bin/bash
cd 'D:/srcdir/srcdir1/'
find . -maxdepth 1 -name '*.csv' \
  -printf 'Handling %f...' \
  -a -exec cSplit.exe {} 'D:/destdir/destdir1/{}' \; \
  -a -exec mv {} ./old/ \; \
  -a -printf 'done\n'

For each .csv file in the D:/srcdir/srcdir1/ directory this will do the following actions in order :

  • Start writing Handling <file name>... on a line
  • Execute cSplit.exe with the first argument being a (relative) path to the file and the second a path to a file with the same name located in the D:/destdir/destdir1/ directory
  • Move the file from the D:/srcdir/srcdir1/ directory to the D:/srcdir/srcdir1/old directory
  • Write one followed by a linefeed on the end of the line.

The actions are joined with -a "AND" operands and will not be taken for a file if the previous action failed (a file for which cSplit.exe thrown an error won't be removed from the initial directory and backed-up, and the "done" will be missing from its line).

You will know no files were found if no output is displayed. If that's not enough for you you can add the following after the find command (needs to be on the same line as the end of the command) : | tee | grep '.' || echo 'no file'

Aaron
  • 24,009
  • 2
  • 33
  • 57