results of wc as variables
Asked Answered
E

8

37

I would like to use the lines coming from 'wc' as variables. For example:

echo 'foo bar' > file.txt
echo 'blah blah blah' >> file.txt
wc file.txt

2  5 23 file.txt

I would like to have something like $lines, $words and $characters associated to the values 2, 5, and 23. How can I do that in bash?

Elianaelianora answered 19/8, 2011 at 9:58 Comment(0)
N
18

There are other solutions but a simple one which I usually use is to put the output of wc in a temporary file, and then read from there:

wc file.txt > xxx
read lines words characters filename < xxx 
echo "lines=$lines words=$words characters=$characters filename=$filename"
lines=2 words=5 characters=23 filename=file.txt

The advantage of this method is that you do not need to create several awk processes, one for each variable. The disadvantage is that you need a temporary file, which you should delete afterwards.

Be careful: this does not work:

wc file.txt | read lines words characters filename

The problem is that piping to read creates another process, and the variables are updated there, so they are not accessible in the calling shell.

Edit: adding solution by arnaud576875:

read lines words chars filename <<< $(wc x)

Works without writing to a file (and do not have pipe problem). It is bash specific.

From the bash manual:

Here Strings

   A variant of here documents, the format is:

          <<<word

   The word is expanded and supplied to the command on its standard input.

The key is the "word is expanded" bit.

Norite answered 19/8, 2011 at 10:7 Comment(4)
Better than mine but You don't need file xxx or filename: wc < file.txt | read lines words charactersFloats
@Adrian: see my comment above: piping creates variables in another process, so they are not available in the calling shell.Norite
read lines words chars <<< $(wc x) works without writing to a file (and do not have pipe problem)Cupulate
@gonvaled: Oh yes, that old trap. @arnaud576875: I haven't seen <<< before!Floats
C
48

In pure bash: (no awk)

a=($(wc file.txt))
lines=${a[0]}
words=${a[1]}
chars=${a[2]}

This works by using bash's arrays. a=(1 2 3) creates an array with elements 1, 2 and 3. We can then access separate elements with the ${a[indice]} syntax.

Alternative: (based on gonvaled solution)

read lines words chars <<< $(wc x)

Or in sh:

a=$(wc file.txt)
lines=$(echo $a|cut -d' ' -f1)
words=$(echo $a|cut -d' ' -f2)
chars=$(echo $a|cut -d' ' -f3)
Cupulate answered 19/8, 2011 at 10:3 Comment(4)
Can you explain why this works? In particular, what do the extra parentheses around the first line do? Without them, it no longer works so they appear to be pretty significant.Burnard
In bash, the outer (...) create an array which the later lines index. Otherwise the result is just aa single string of three numbersFloats
In this case, the parentheses are part of the $(command) command substitution syntax; it is equivalent to `command`, but the parenthesis notation simplifies nesting. The command is run in a subshell, and the text of the command substitution is replaced by the output of command, almost as if you had typed it.Denysedenzil
The "almost as if" is because a=x y z assigns x to a and then runs the command y z; a=(x y z) assigns x, y, and z to the array a, but you don't have to type the extra parens as in a=($(echo x y z)) because the word splitting happens later.Denysedenzil
N
18

There are other solutions but a simple one which I usually use is to put the output of wc in a temporary file, and then read from there:

wc file.txt > xxx
read lines words characters filename < xxx 
echo "lines=$lines words=$words characters=$characters filename=$filename"
lines=2 words=5 characters=23 filename=file.txt

The advantage of this method is that you do not need to create several awk processes, one for each variable. The disadvantage is that you need a temporary file, which you should delete afterwards.

Be careful: this does not work:

wc file.txt | read lines words characters filename

The problem is that piping to read creates another process, and the variables are updated there, so they are not accessible in the calling shell.

Edit: adding solution by arnaud576875:

read lines words chars filename <<< $(wc x)

Works without writing to a file (and do not have pipe problem). It is bash specific.

From the bash manual:

Here Strings

   A variant of here documents, the format is:

          <<<word

   The word is expanded and supplied to the command on its standard input.

The key is the "word is expanded" bit.

Norite answered 19/8, 2011 at 10:7 Comment(4)
Better than mine but You don't need file xxx or filename: wc < file.txt | read lines words charactersFloats
@Adrian: see my comment above: piping creates variables in another process, so they are not available in the calling shell.Norite
read lines words chars <<< $(wc x) works without writing to a file (and do not have pipe problem)Cupulate
@gonvaled: Oh yes, that old trap. @arnaud576875: I haven't seen <<< before!Floats
O
5
lines=`wc file.txt | awk '{print $1}'`
words=`wc file.txt | awk '{print $2}'`
...

you can also store the wc result somewhere first.. and then parse it.. if you're picky about performance :)

Overarch answered 19/8, 2011 at 10:1 Comment(0)
P
4

Just to add another variant --

set -- `wc file.txt`
chars=$1
words=$2
lines=$3

This obviously clobbers $* and related variables. Unlike some of the other solutions here, it is portable to other Bourne shells.

Praseodymium answered 19/8, 2011 at 10:23 Comment(0)
L
4

I wanted to store the number of csv file in a variable. The following worked for me:

CSV_COUNT=$(ls ./pathToSubdirectory | grep ".csv" | wc -l | xargs)
  • xargs removes the whitespace from the wc command
  • I ran this bash script not in the same folder as the csv files. Thus, the pathToSubdirectory
Lover answered 18/10, 2018 at 7:58 Comment(0)
B
0

You can assign output to a variable by opening a sub shell:

$ x=$(wc some-file)
$ echo $x
1 6 60 some-file

Now, in order to get the separate variables, the simplest option is to use awk:

$ x=$(wc some-file | awk '{print $1}')
$ echo $x
1
Burnard answered 19/8, 2011 at 10:2 Comment(0)
F
0
declare -a result
result=( $(wc < file.txt) )
lines=${result[0]}
words=${result[1]}
characters=${result[2]}
echo "Lines: $lines, Words: $words, Characters: $characters"
Floats answered 19/8, 2011 at 10:8 Comment(0)
N
0

Another alternative.

$ read lines words chars _ < <( wc file.txt )
$ printf 'lines: %s\nwords: %s\nchars: %s\n' $lines $words $chars

lines: 2
words: 5
chars: 23
Namhoi answered 12/5 at 12:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.