1836648 Members
1839 Online
110102 Solutions
New Discussion

a simple shell

 
SOLVED
Go to solution
Michael_33
Regular Advisor

a simple shell

i have a directory called /abc, there are many
files in it, some are named start with 33567,
now i want only keep the file which name are 33567*, the rest files all move to /xyz.

how to do it?
thx, high score if reply
19 REPLIES 19
harry d brown jr
Honored Contributor

Re: a simple shell

cd /
find ./abc -type f \( ! -name "33567*" \) -exec mv {} ./xyz \;

live free or die
harry d brown jr
Live Free or Die
Michael_33
Regular Advisor

Re: a simple shell

thx! any other ways?
sry for the 7 points, pls reply i will assgin 10 points to U!
Devender Khatana
Honored Contributor

Re: a simple shell

Hi,

Try this
#find /abc -name "33567*" -print |cpio -pdmv /xyz

HTH,
Devender
Impossible itself mentions "I m possible"
Michael_33
Regular Advisor

Re: a simple shell

can it do with awk or for loop?

john korterman
Honored Contributor

Re: a simple shell

Hi,

# cd /abc
# mv $(ls | grep -v "^33567*") /xyz

regards,
John K.
it would be nice if you always got a second chance
Patrick Wallek
Honored Contributor
Solution

Re: a simple shell

You might be able to do it with awk, but awk is really not the ideal tool for this.

Yet another way:

cd /abc
ls -1 | grep -v 33567 > /var/tmp/afile

(verify contents of /var/tmp/afile here to make sure it is only what you require)

for file in $(cat /var/tmp/afile)
do
mv /abc/${file} /xyz
done

Michael_33
Regular Advisor

Re: a simple shell

good!

the previous replier pls reply, i will assign 3 more ponits to U! (7+3=10)
harry d brown jr
Honored Contributor

Re: a simple shell

other ways? Sure: You can write a perl script, a shell script or even a program, but that simple one liner is probably the easiest.

The cpio solution given will NOT work:
o It will move the files 33567* to xyz
o It does not remove the files copied from abc to xyz
o it is using an absolute path which will not work, so /xyz would end up having /xyc/tmp/abc (see example:)

[root@vpart1 /tmp]# ls -l abc xyz

abc:
total 0
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_1
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_2
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_3
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_4
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_1
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_2
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_3
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_4

xyz:
total 0
[root@vpart1 /tmp]# find /tmp/abc -type f \( ! -name "33567*" \) -print | cpio -pdvm /tmp/xyz
/tmp/xyz/tmp/abc/33568_1
/tmp/xyz/tmp/abc/33568_2
/tmp/xyz/tmp/abc/33568_3
/tmp/xyz/tmp/abc/33568_4
0 blocks

[root@vpart1 /tmp]# ls -lR abc xyz

abc:
total 0
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_1
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_2
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_3
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33567_4
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_1
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_2
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_3
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_4

xyz:
total 0
drwxrwxrwx 3 root sys 96 Apr 25 09:40 tmp

xyz/tmp:
total 0
drwxrwxrwx 2 root sys 96 Apr 25 09:40 abc

xyz/tmp/abc:
total 0
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_1
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_2
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_3
-rw-rw-rw- 1 root sys 0 Apr 25 09:06 33568_4
[root@vpart1 /tmp]#


so stick with the "mv"


live free or die
harry d brown jr
Live Free or Die

Re: a simple shell

the Korn shell has built in pattern matching - for example...

$ ksh
$ cd /abc
$ mv !(33567*) /xyz


No need for a loop. But if you like them...

$ksh
$ cd /abc
$ for i in !(33567*)
do
mv $i /xyz
done
Hello World
harry d brown jr
Honored Contributor

Re: a simple shell

Chris,

Both examples will fail if there are a LOT (thousands) of files, which is why a "find" with an "exec mv" works the best.

live free or die
harry d brown jr
Live Free or Die

Re: a simple shell

Harry,

I agree with you about my first example. But I think the second works even when there are LOTS of matches. At least that been my experience with other enviroments (Tru64 UNIX and other older machines). My HP-UX box refuses to go wrong either way - I clearly don't have enough files.

Chris.
Hello World
harry d brown jr
Honored Contributor

Re: a simple shell

Chris,

You could encounter this:

#foo=0
#for i in `find / -type f` ^Jdo^Jfoo=`expr $foo + 1`^Jdone

sh: There is not enough memory available now.


live free or die
harry d brown jr

Live Free or Die

Re: a simple shell

Harry,

As Manuel In Fawlty Towers might say; 'Que?'
Hello World
Cem Tugrul
Esteemed Contributor

Re: a simple shell

Hi Michael,

how about this?

cd /targetdir

for file in `ls -lrt|awk '$9~/33567*/{print $9}'`
do
whatever you want
done

Good Luck,
Our greatest duty in this life is to help others. And please, if you can't
Nguyen Anh Tien
Honored Contributor

Re: a simple shell

Hi Michael
I like to do like this
$ mv !(33567*) /xyz
//defauld shell of HP UX 11i is posfix
some things like Chris Shepherd solution
HTH
HP is simple
Bob_Vance
Esteemed Contributor

Re: a simple shell

IMHO, the best and most general way is the 'find' command as mentioned by Harry and Devender.

Any other way that uses an in-line string could, as also mentioned, cause a memory overflow error. Perhaps not on your current HPUX, whose new command buffer size is very large, but if you try it on older HPUX or other Unixes, it could be an issue. Plus, 'find' is very powerful and useful and you should learn how to use it!!

For example, even Patick's command could have a problem:

for file in $(cat /var/tmp/afile)
do
mv /abc/${file} /xyz
done

since the results of the 'cat' are used in-line.

When doing something like Patrick's example and when the size is unknown, I generally do it this way:

while read f
do
mv /abc/${f} /xyz
done < /var/tmp/afile

where the shell is directly reading "/var/tmp/afile" (the re-direct must be placed on the 'done').
This technique (shell loop reading input into a variable) is a great one to know.
This method works no matter how large "/var/tmp/afile" might be, and it doesn't require the extra pipe and cat process.

However, for readability when I might not be the only one ever to look at the script, I sometimes use the slightly less efficient:

cat /var/tmp/afile \
| while read f
do
mv /abc/${f} /xyz
done


HTH
bv

"The lyf so short, the craft so long to lerne." - Chaucer
harry d brown jr
Honored Contributor

Re: a simple shell

Bob,

Thanks.

That memory error was from a machine that is very current in patches and has 2.5 Gb of memory with the following limits:
[root@vpart1 /var/adm/syslog]# ulimit -a
time(seconds) unlimited
file(blocks) unlimited
data(kbytes) 262144
stack(kbytes) 8192
memory(kbytes) unlimited
coredump(blocks) 4194303
nofiles(descriptors) 512

I agree that any process that tries to do "INLINE" globbing will some day DIE a nasty death and everyone will look at themselves and say "it's worked like that for years, why did it die?" - answer -> Shitty coding.

a personal quote "anyone can write a program, but not everyone can be a programmer"

live free or die
harry d brown jr

Live Free or Die

Re: a simple shell

I think there is a lot of confusion here, at the risk of adding to it here is a fuller explanation of my earlier postâ ¦

When the shell executes a command it expands expressions and then calls exec(2). Exec is limited by a buffer which is defined by ARG_MAX (to see yours type - getconf ARG_MAX).

So when the command expands to a list (plus environment variables) that is greater than ARG_MAX you get an â arg list too longâ error message. So as I said before - I agree that my first example can fail (see below**).

In the â for loopâ example however, although the expansion of !(33567*) is still performed by the shell, the result of the expansion is not being passed to another program. So the kernel's limit on the size of the exec(2) argument does not come into play.

** If you have the latest HP-UX your ARG_MAX should be 2Mb thatâ
Hello World
Bob_Vance
Esteemed Contributor

Re: a simple shell

Chris,
Good points.

But, simply stated, if you use command line strings, then it's not a general solution -- i.e., it's not guaranteed to work in all cases.

However, your point is interesting. I haven't looked at the source and I wonder how the shell actually generates the results of a *. Probably malloc'ing memory on the fly. And you would be right -- if the shell didn't have to pass it, he could use it directly himself. Still, it is *theoretically* possible for the shell process to run out of memory or even swap space ;>)


bv
"The lyf so short, the craft so long to lerne." - Chaucer