Fedora Linux Support Community & Resources Center
  #1  
Old 1st April 2012, 12:08 PM
firefexx Offline
Registered User
 
Join Date: Oct 2009
Location: /home
Posts: 113
linuxfirefox
Little Bash Problem

Hi, I'm out to write a script which reads a text file and copies all words into another text file if their length is 8.
But I can't get it work :[

Code:
#!/bin/sh

for word  in $(cat list1.txt); do

    if [ $(#word) -eq 8 ]; then
        echo $word >> list2.txt
    fi
    
done
Can somebody tell me what is wrong?
Reply With Quote
  #2  
Old 1st April 2012, 12:48 PM
glennzo Online
Un-Retired Administrator
 
Join Date: Mar 2004
Location: Salem, Mass USA
Age: 57
Posts: 14,867
linuxfirefox
Re: Little Bash Problem

Replace the () with {}

PHP Code:
if [ ${#word} -eq 8 ] ; then 
This seems to work for me.
__________________
Glenn
The Bassinator © ®

[SIGPIC][/SIGPIC]
Laptop: Just a couple of old single core units
Desktop: BioStar MCP6PB M2+ / AMD Phenom 9750 Quad Core / 4GB / Kingston HyperX 3K SSD 240GB SATA 3.0 / 1TB SATA / EVGA GeForce 8400 GS 1GB
Reply With Quote
  #3  
Old 1st April 2012, 01:14 PM
firefexx Offline
Registered User
 
Join Date: Oct 2009
Location: /home
Posts: 113
linuxfirefox
Re: Little Bash Problem

Yes it works. Thanks!

But can you explain me why? The syntax confuses me.
Reply With Quote
  #4  
Old 1st April 2012, 01:22 PM
jpollard Online
Registered User
 
Join Date: Aug 2009
Location: Waldorf, Maryland
Posts: 6,898
linuxfirefox
Re: Little Bash Problem

() is used to designate a subprocess to be executed
{} is used to encapsulate a variable that may be confused with characters outside the {}.

$ is used to signify a substition point - hence $( makes no sense.

Now arithemtic expressions are identified by $((<expression>))
might have worked.
Reply With Quote
  #5  
Old 1st April 2012, 08:32 PM
Gareth Jones Offline
Official Gnome 3 Sales Rep. (and Adminstrator)
 
Join Date: Jul 2011
Location: Birmingham, UK
Age: 32
Posts: 2,771
linuxfirefox
Re: Little Bash Problem

Quote:
Originally Posted by jpollard View Post
$ is used to signify a substition point - hence $( makes no sense.
Just to clarify, $(command) does make sense, and captures the output of a command. It's a more modern syntax for `command` (with back-ticks rather than single-quotes, which mean a literal string with no internal substitutions in shell-script). However, variables are expanded with $var or ${var}.

So:
Code:
# Literal string with internal substitution (spaces do not split tokens):
$ echo "$PATH"
/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/gareth/.local/bin:/home/gareth/bin

# Literal string without internal substitution (spaces do not split tokens):
$ echo '$PATH'
$PATH

# Capture command output:
$ echo `ls /`
bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
$ echo $(ls /)
bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var

# Substitute a variable (spaces split tokens unless the variable is double-quoted):
$ echo $PATH
/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/gareth/.local/bin:/home/gareth/bin
$ echo ${PATH}
/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/gareth/.local/bin:/home/gareth/bin

# Do integer maths:
$ echo $((1 + 23))
24
$ echo $[1 + 23]
24


---------- Post added at 08:32 PM ---------- Previous post was at 08:27 PM ----------

I'd also make the following (very minor!) optimizations:
Code:
#!/bin/sh

for word  in $(< list1.txt); do

    if [ ${#word} -eq 8 ]; then
        echo $word >> list2.txt
    fi
    
done > list2.txt
The first change uses the bash internal file reader rather than running cat as a separate process.

The second causes list2.txt to only be opened and closed once.
Reply With Quote
  #6  
Old 2nd April 2012, 01:03 AM
stevea Offline
Registered User
 
Join Date: Apr 2006
Location: Ohio, USA
Posts: 9,041
linuxfirefox
Re: Little Bash Problem

Quote:
Originally Posted by jpollard View Post
() is used to designate a subprocess to be executed
No - wrong - it's a SUB-SHELL - same shell but new environment - NOT a subprocess.

Also () can be used to modify default precedence, pattern matching in a case statement, in bash function declarations, in array assignment ; e.g: FOO=([0]="foo" [1]="bar" [2]="baz")
Used as <(list) or >(list) to create pipes.

Quote:
{} is used to encapsulate a variable that may be confused with characters outside the {}.
More accurately ....
Quote:
${parameter}
The value of parameter is substituted. The braces are required when parameter is a positional parameter with more than one digit, or when parameter is followed by a character which is not to be interpreted as part of its name.
So it delimits parameters where there is the possibility of confusion. A shell variable is one type of parameter, and that's only one of several uses for braces. Brace expansion, function declaration, same-shell lists, ...


Quote:
Originally Posted by Gareth Jones View Post
Just to clarify, ....
Excellent changes.
__________________
None are more hopelessly enslaved than those who falsely believe they are free.
Johann Wolfgang von Goethe
Reply With Quote
  #7  
Old 2nd April 2012, 01:55 AM
Gareth Jones Offline
Official Gnome 3 Sales Rep. (and Adminstrator)
 
Join Date: Jul 2011
Location: Birmingham, UK
Age: 32
Posts: 2,771
linuxfirefox
Re: Little Bash Problem

Quote:
Originally Posted by stevea View Post
No - wrong - it's a SUB-SHELL - same shell but new environment - NOT a subprocess.
A "( command )" sub-shell is generally implemented as a separate child process of the main shell though. "{ command ;}" is similar, but tries to run commands in the current shell whenever possible (pipes for example make that difficult):
Code:
[gareth@gareth-desktop ~]$ echo $BASHPID  # Main shell process ID.
19613
[gareth@gareth-desktop ~]$ ( echo $BASHPID )  # Subshell has new PID.
19717
[gareth@gareth-desktop ~]$ { echo $BASHPID; }  # Should have same PID.
19613
[gareth@gareth-desktop ~]$ echo hello | { echo $BASHPID; cat ;}  # Pipe forces sub-shell.
19761
hello
Note that $$ always expands to the main shell's PID, so you have to use $BASHPID to catch the sub-shell.
Reply With Quote
  #8  
Old 2nd April 2012, 06:11 AM
RupertPupkin Offline
Registered User
 
Join Date: Nov 2006
Location: Detroit
Posts: 5,769
linuxfedorafirefox
Re: Little Bash Problem

I prefer to use a while loop:
Code:
#!/bin/bash
while read -r word; do
   if [ ${#word} -eq 8 ]; then
      echo $word
   fi
done < list1.txt > list2.txt
__________________
OS: Fedora 21 x86_64 | Machine: HP Pavilion a6130n | CPU: AMD 64 X2 Dual-Core 5000+ 2.6GHz | RAM: 5GB PC5300 DDR2 | Disk: 400GB SATA | Video: ATI Radeon HD 4350 512MB | Sound: Realtek ALC888S | Ethernet: Realtek RTL8201N
Reply With Quote
  #9  
Old 2nd April 2012, 07:36 AM
stevea Offline
Registered User
 
Join Date: Apr 2006
Location: Ohio, USA
Posts: 9,041
linuxfirefox
Re: Little Bash Problem

Quote:
Originally Posted by Gareth Jones View Post
A "( command )" sub-shell is generally implemented as a separate child process of the main shell though. "{ command ;}" is similar, but tries to run commands in the current shell whenever possible (pipes for example make that difficult):

Thanks - I haven't examinined the implementation in many years - but it it's create using ...
strace -f -etrace=clone,execve bash

So both "(cmd)" and "cmd&" so a fork a subprocess currently, and neither does an exec (aside from any exceutable cmd exec). "{cmd;}", as expected executes w/o any extra process creation.


I don't think your comments about pipes is clear (and maybe not accurate). We expect pipes "|" to create new processes .... for example
ls | wc -l
vs
{ ls | wc -l; }

have the same process creation events. Ignoring the execve() calls for the executables, there is always one clone() "aka fork" call per pipe .....

(output line length below trimmed for clarity)
Quote:
[stevea@crucibulum Desktop]$ ls | wc -l
clone(Process 24114 attached
[pid 23534] clone(Process 24115 attached
Process 23534 suspended
[pid 24114] execve("/bin/ls", ["ls"], [/* 49 vars */]) = 0
[pid 24115] execve("/usr/bin/wc", ["wc", "-l"], [/* 49 vars */]) = 0
17
Process 23534 resumed
Process 24114 detached
Process 24115 detached

[stevea@crucibulum Desktop]$ { ls | wc -l; }
clone(Process 24116 attached
[pid 23534] clone(Process 24117 attached
Process 23534 suspended
[pid 24116] execve("/bin/ls", ["ls"], [/* 49 vars */]) = 0
[pid 24117] execve("/usr/bin/wc", ["wc", "-l"], [/* 49 vars */]) = 0
Process 23534 resumed
Process 24116 detached
17
Process 23534 suspended
Process 23534 resumed
Process 24117 detached
__________________
None are more hopelessly enslaved than those who falsely believe they are free.
Johann Wolfgang von Goethe
Reply With Quote
  #10  
Old 2nd April 2012, 02:13 PM
firefexx Offline
Registered User
 
Join Date: Oct 2009
Location: /home
Posts: 113
linuxfirefox
Re: Little Bash Problem

Ok, thanks for all the answers
Reply With Quote
  #11  
Old 2nd April 2012, 02:55 PM
Gareth Jones Offline
Official Gnome 3 Sales Rep. (and Adminstrator)
 
Join Date: Jul 2011
Location: Birmingham, UK
Age: 32
Posts: 2,771
linuxfirefox
Re: Little Bash Problem

Quote:
Originally Posted by RupertPupkin View Post
I prefer to use a while loop:
Code:
#!/bin/bash
while read -r word; do
   if [ ${#word} -eq 8 ]; then
      echo $word
   fi
done < list1.txt > list2.txt
That's the best way I think.

---------- Post added at 02:55 PM ---------- Previous post was at 02:51 PM ----------

Quote:
Originally Posted by stevea View Post
I don't think your comments about pipes is clear (and maybe not accurate). We expect pipes "|" to create new processes
Yes, I was probably going into too much detail and then over-simplifying it back. The reason I thought of it is that I remember some other Bourne shell derivatives (ksh maybe?) can run the last part of a pipe-line in the top-level shell so that you can read into shell variables etc. for use later. In Bash you'd have to use process substitution instead I think. But none of that directly relates to sub-shell syntaxes of course.
Reply With Quote
Reply

Tags
bash, problem

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
bash problem HayZam Using Fedora 4 25th January 2008 02:39 PM
bash problem mohdfarah Programming & Packaging 0 17th September 2006 12:41 PM


Current GMT-time: 03:32 (Monday, 22-12-2014)

TopSubscribe to XML RSS for all Threads in all ForumsFedoraForumDotOrg Archive
logo

All trademarks, and forum posts in this site are property of their respective owner(s).
FedoraForum.org is privately owned and is not directly sponsored by the Fedora Project or Red Hat, Inc.

Privacy Policy | Term of Use | Posting Guidelines | Archive | Contact Us | Founding Members

Powered by vBulletin® Copyright ©2000 - 2012, vBulletin Solutions, Inc.

FedoraForum is Powered by RedHat
...Berlin Airport Travel Photos - Shangrila Mall Photos - Laguna Verde , Valparaiso - Hotel Madanis Barcelona Photos on Instagram