Discussion:
[Help-bash] if exist
Val Krem
2017-05-13 01:21:32 UTC
Permalink
Hi all,


I have list of files in a given folder and some of these files are ending with any digit(starting from 1 up to may be 9 or more). My aim is if a file name is ending with any digit number then I want copy it to other folder and suppress the error message generated if the file does not exist in the folder.

Sample of list of files
xbx1.txt1
xby2.txt2
xcx3.txt3
xxx1.txt4
xxy1.txt5

Below is my attempt.

#! /bin/bash

dat0=/data/val1
dat1=/data/val2
shopt -s extglob
cd ${dat0}
xc=$(ls x*'.'txt{1..10})
echo $xc

for i in $(xc);do
if [ ${xc} ];then
cp ${xc} $dat1
fi
done

But did not work.
Can some one help me out?
Pierre Gaston
2017-05-13 04:54:45 UTC
Permalink
Post by Val Krem
Hi all,
I have list of files in a given folder and some of these files are ending
with any digit(starting from 1 up to may be 9 or more). My aim is if a
file name is ending with any digit number then I want copy it to other
folder and suppress the error message generated if the file does not exist
in the folder.
Sample of list of files
xbx1.txt1
xby2.txt2
xcx3.txt3
xxx1.txt4
xxy1.txt5
Below is my attempt.
There are many problems, I'll comment on the ones more relevant to your
immediate problem
Post by Val Krem
#! /bin/bash
dat0=/data/val1
dat1=/data/val2
shopt -s extglob
cd ${dat0}
xc=$(ls x*'.'txt{1..10})
echo $xc
for i in $(xc);do
This doesn't work at all, $( ) will run a command named "xc" it would have
worked a
bit better if you have used $xc which would have expanded the variable and
loop on each word.
However there is a much cleaner and simpler way:

xc=( x*.txt{1...10) # this create an array variable with the file matching
for i in "${xc[@]}";do # this will loop on the elements of the array. note
the " "
Post by Val Krem
if [ ${xc} ];then
This tests if the variable ${xc} is a string with characters, not if the
file exists.
So first you want to test "$i" since "xc" contains all the filenames, i is
the variable
that gets the individual filenames.
then you want to test if the file exists for this you need to use the "-e"
or "-f" test:

if [ -e "$i" ]; then #again note the double quotes they avoid problems
with spaces, glob etc.
Post by Val Krem
cp ${xc} $dat1
here you want $i again
cp "$i" "$dat1"
Post by Val Krem
fi
done
to sum up:
#! /bin/bash

dat0=/data/val1
dat1=/data/val2
shopt -s extglob

if ! cd "${dat0}"; then
echo "could not change directory to $dat0"
fi
xc=(x*'.'txt{1..10})
echo "${xc[@]}"

for i in "${xc[@]}";do
if [ -e "${i}" ];then
cp "$i" "$dat1"
fi
done

Some links you may want to check:

http://mywiki.wooledge.org/BashGuide
http://mywiki.wooledge.org/BashPitfalls
http://mywiki.wooledge.org/BashFAQ
http://www.shellcheck.net/
Val Krem
2017-05-13 12:56:44 UTC
Permalink
Thank you so much Piere!


xc=("$dat0"/x*'.'txt{1..10})
echo "${xc[@]}"
for i in "${xc[@]}";do
if [ -e "${i}" ];then
cp "$i" "$dat1 "
fi
done


One more question,though.
if there are several files ending with the same digit number only the first one was copied.

xbx1.txt1
xby2.txt1
If it possible to accommodate this well? Instead of writing twice the script twice depending on the file patterns


Thank you again.
Post by Val Krem
Hi all,
I have list of files in a given folder and some of these files are ending
with any digit(starting from 1 up to may be 9 or more). My aim is if a
file name is ending with any digit number then I want copy it to other
folder and suppress the error message generated if the file does not exist
in the folder.
Sample of list of files
xbx1.txt1
xby2.txt2
xcx3.txt3
xxx1.txt4
xxy1.txt5
Below is my attempt.
There are many problems, I'll comment on the ones more relevant to your
immediate problem
Post by Val Krem
#! /bin/bash
dat0=/data/val1
dat1=/data/val2
shopt -s extglob
cd ${dat0}
xc=$(ls x*'.'txt{1..10})
echo $xc
for i in $(xc);do
This doesn't work at all, $( ) will run a command named "xc" it would have
worked a
bit better if you have used $xc which would have expanded the variable and
loop on each word.
However there is a much cleaner and simpler way:

xc=( x*.txt{1...10) # this create an array variable with the file matching
for i in "${xc[@]}";do # this will loop on the elements of the array. note
the " "
Post by Val Krem
if [ ${xc} ];then
This tests if the variable ${xc} is a string with characters, not if the
file exists.
So first you want to test "$i" since "xc" contains all the filenames, i is
the variable
that gets the individual filenames.
then you want to test if the file exists for this you need to use the "-e"
or "-f" test:

if [ -e "$i" ]; then #again note the double quotes they avoid problems
with spaces, glob etc.
Post by Val Krem
cp ${xc} $dat1
here you want $i again
cp "$i" "$dat1"
Post by Val Krem
fi
done
to sum up:
#! /bin/bash

dat0=/data/val1
dat1=/data/val2
shopt -s extglob

if ! cd "${dat0}"; then
echo "could not change directory to $dat0"
fi
xc=(x*'.'txt{1..10})
echo "${xc[@]}"

for i in "${xc[@]}";do
if [ -e "${i}" ];then
cp "$i" "$dat1"

fi
done

Some links you may want to check:

http://mywiki.wooledge.org/BashGuide
http://mywiki.wooledge.org/BashPitfalls
http://mywiki.wooledge.org/BashFAQ
http://www.shellcheck.net/
Pierre Gaston
2017-05-13 14:20:37 UTC
Permalink
Post by Val Krem
Thank you so much Piere!
xc=("$dat0"/x*'.'txt{1..10})
if [ -e "${i}" ];then
cp "$i" "$dat1 "
fi
done
One more question,though.
if there are several files ending with the same digit number only the first one was copied.
xbx1.txt1
xby2.txt1
If it possible to accommodate this well? Instead of writing twice the
script twice depending on the file patterns
With the above code (well without the extra space inside "$dat1 "), it
copies both the files you list.
So please paste your exact problem.

http://ideone.com/5FpIzH
John McKown
2017-05-13 12:46:08 UTC
Permalink
Post by Val Krem
Hi all,
I have list of files in a given folder and some of these files are ending
with any digit(starting from 1 up to may be 9 or more). My aim is if a
file name is ending with any digit number then I want copy it to other
folder and suppress the error message generated if the file does not exist
in the folder.
Sample of list of files
xbx1.txt1
xby2.txt2
xcx3.txt3
xxx1.txt4
xxy1.txt5
Below is my attempt.
#! /bin/bash
dat0=/data/val1
dat1=/data/val2
shopt -s extglob
cd ${dat0}
xc=$(ls x*'.'txt{1..10})
echo $xc
for i in $(xc);do
if [ ${xc} ];then
cp ${xc} $dat1
fi
done
But did not work.
Can some one help me out?
​dat0=/data/va21 # "from" directory
dat1=/data/val2​ # "to" directory
find "${dat0}" -mindepth 1 -maxdepth 1 -type f -regexptype egrep -regex
'.*[0-9]$' | xargs -I {} cp -a {} "${dat1}"

Basically, "find" will do all work of finding the file names for you.
-mindepth 1 & -maxdepth 1 together says "only look for entries in _this_
directory (not in subdirectories)"
-type f means "only match regular files (not subdirectory names or symlinks
or ???)"
-regexptype egrep "use an extended regular expression"
-regex is the regular expression (extended per above) which is "any number
of characters followed by a trailing digit"

All of the files found will be fed into "xargs" which will construct a "cp"
command to do the actual work. Note that if there are a lot of file, this
may exceed the command buffer size. In that case, on the "xargs" command,
before the "-I' portion use "-n ..." switch to only copy ... files at a
time. xargs will split the files into groups that are ... entries long and
invoke "cp" as many times as necessary to get them all copies. E.g. if you
want to copy 10 at a time use:

... | xargs -n 10 -I {} cp -a {} "${dat1}"
--
Advertising is a valuable economic factor because it is the cheapest way of
selling goods, particularly if the goods are worthless. -- Sinclair Lewis


Maranatha! <><
John McKown
Greg Wooledge
2017-05-15 12:23:20 UTC
Permalink
Post by John McKown
find "${dat0}" -mindepth 1 -maxdepth 1 -type f -regexptype egrep -regex
'.*[0-9]$' | xargs -I {} cp -a {} "${dat1}"
Why would you use
-regexptype egrep -regex '.*[0-9]$'

when you could simply (and portably!) use
-name '*[0-9]'

That said, with -mindepth 1 and -maxdepth 1, it looks like you are not
recursing at all. So you could just use a glob.

cd "$someplace" || exit
for file in *[0-9]; do
base=${file%[0-9]}
whatever "$file" "$base"
....
done
John McKown
2017-05-15 12:26:07 UTC
Permalink
Post by Greg Wooledge
Post by John McKown
find "${dat0}" -mindepth 1 -maxdepth 1 -type f -regexptype egrep -regex
'.*[0-9]$' | xargs -I {} cp -a {} "${dat1}"
Why would you use
-regexptype egrep -regex '.*[0-9]$'
when you could simply (and portably!) use
-name '*[0-9]'
​I'm insane? [grin]. Or I've been brain damaged by too much PERL?​
Post by Greg Wooledge
That said, with -mindepth 1 and -maxdepth 1, it looks like you are not
recursing at all. So you could just use a glob.
cd "$someplace" || exit
for file in *[0-9]; do
base=${file%[0-9]}
whatever "$file" "$base"
....
done
--
Advertising is a valuable economic factor because it is the cheapest way of
selling goods, particularly if the goods are worthless. -- Sinclair Lewis


Maranatha! <><
John McKown
Loading...