Gentoo Archives: gentoo-user

From: Florian Philipp <lists@×××××××××××.net>
To: gentoo-user@l.g.o
Subject: Re: [gentoo-user] OT: cut replacement with bash builtins
Date: Sun, 27 Feb 2011 22:10:23
Message-Id: 4D6ACB6A.7020301@binarywings.net
In Reply to: Re: [gentoo-user] OT: cut replacement with bash builtins by Alex Schuster
1 Am 27.02.2011 22:06, schrieb Alex Schuster:
2 > Florian Philipp writes:
3 >
4 >> I'm currently streamlining some of my shell scripts to avoid unnecessary
5 >> process calls where bash itself is powerful enough.
6 >>
7 >> At the moment, I want to replace stuff like this:
8 >> string='foo:bar:foo'
9 >> second_field=$(echo $string | cut -d : -f 2) # should read "bar"
10 >>
11 >> My current solution is using two string operations:
12 >> string='foo:bar:foo'
13 >> # remove everything up to and including first ':'
14 >> second_and_following=${string#*:}
15 >> # remove everything from the first ':' following
16 >> second_field=${second_and_following%%:*}
17 >
18 > That's how I do these things, too.
19 >
20 >> Of course, I normally do this in a single line with a subshell but it
21 >
22 > Hmm, I don't get this. Subshell?
23
24 second_field=$(second_and_following=${string#*:}; echo
25 ${second_and_following%%:*})
26
27 Putting it in parentheses creates a subshell. New variables don't leave
28 the scope. I guess I should have said command substitution but both
29 concepts apply here.
30
31 >
32 >> still looks cumbersome. Is there a way to do it in a single operation
33 >> without a temporary variable? The following does not work:
34 >> string='foo:bar:foo'
35 >> second_field=${string#:%%:*}
36 >
37 > I don't think so. But you can write a shell function for this:
38 >
39 > getfield()
40 > {
41 > local str=${1#*:}
42 > echo "${str%%:*}
43 > }
44 >
45 > string='foo:bar:foo'
46 > second_field=$( getfield "$string" )
47 >
48 > But if you need to do this very often in a loop, sometimes going back to
49 > cut can speed things up, when you place it outside:
50 >
51 > See
52 >
53 > for string in $( < inputfile )
54 > do
55 > second_field=$( getfield "$string" )
56 > do_something_with $second_field
57 > done
58 >
59 > vs.
60 >
61 > secondfields=( $( cut -d : -f 2 inputfile ) )
62 > for secondfield in ${secondfields[@]}
63 > do
64 > do_something_with $second_field
65 > done
66 >
67 > So, in th e2nd example, cut is called only once, but processes all input
68 > lines. The result is put into an array.
69 >
70
71 Agreed. Using one long pipe (when applicable) is the real strength of
72 shell programming.
73
74 > Of course, all stuff should be put into double quotes in case there is
75 > whitescape involved. Setting IFS to $'\n' may be necessary for this when
76 > creating the array.
77 >
78 > Wonko
79 >
80
81 Agreed, again. I removed the quotes from my examples to improve
82 readability. It was already bad enough with all those regular expressions.
83
84 Thanks for the input.
85
86 Florian Philipp

Attachments

File name MIME type
signature.asc application/pgp-signature