30

I have an operation using cut that I would like to assign result to a variable

var4=echo ztemp.xml |cut -f1 -d '.'

I get the error:

ztemp.xml is not a command

The value of var4 never gets assigned; I'm trying to assign it the output of:

echo ztemp.xml | cut -f1 -d '.'

How can I do that?

0

4 Answers 4

43

You'll want to modify your assignment to read:

var4="$(echo ztemp.xml | cut -f1 -d '.')"

The $(…) construct is known as command susbtitution.

2
  • 9
    @Vass: Better: var4=$(echo ztemp.xml | cut -f1 -d '.'). $(…) is mostly equivalent to ` `…` , except that quoting inside backquotes is peculiar (and in particular nesting backquotes is not recommended), whereas quoting inside $(…)` is unusually intuitive. Furthermore $(…) is more readable than ` `…` ` which is easily confused with '…' in many fonts. So if you're going to learn only one, learn $(…). Dec 6, 2010 at 22:25
  • 1
    though the question explicitly states that the user wants to assign the output of a command to a variable, his intention in this case is very clearly to strip the file extension. since your answer has already been accepted, it would be most polite of you to update it to include tips from Dennis's answer below.
    – Josh McGee
    Jul 23, 2013 at 19:26
9

Depending on the shell you're using, you can use Parameter Expansion. For instance in bash:

   ${parameter%word}
   ${parameter%%word}
          Remove matching suffix pattern.  The word is expanded to produce
          a pattern just as in pathname expansion.  If the pattern matches
          a trailing portion of the expanded value of parameter, then  the
          result  of the expansion is the expanded value of parameter with
          the shortest matching pattern (the ``%'' case)  or  the  longest
          matching  pattern  (the ``%%'' case) deleted.  If parameter is @
          or *, the pattern removal operation is  applied  to  each  posi‐
          tional  parameter  in  turn,  and the expansion is the resultant
          list.  If parameter is an array variable subscripted with  @  or
          *,  the  pattern  removal operation is applied to each member of
          the array in turn, and the expansion is the resultant list.

In your case that would mean doing something like this:

var4=ztemp.xml
var4=${var4%.*}

Note that the character # behaves in a similar way on the prefix part of the string.

1
  • And use ${var4%%.*} to exactly match the original behavior for strings with multiple dots (e.g. foo.xml.gz). Dec 7, 2010 at 16:28
8

Ksh, Zsh and Bash all offer another, perhaps clearer syntax:

var4=$(echo ztemp.xml | cut -f1 -d '.')

The backticks (a.k.a. "grave accent") is unreadable in some fonts. The $(blahblah) syntax is a lot more obvious at least.

Note that you can pipe values into a read command in some shells:

ls -1 \*.\* | cut -f1 -d'.' | while read VAR4; do echo $VAR4; done
9
  • 2
    $() is specified by POSIX, so it's also available in Dash, Ash, and others. Piping into read won't work in Bash. Dec 6, 2010 at 22:07
  • @DennisWilliamson you can pipe into read, you just cant do it like that (if you want the variable to be accessible outside the loop): while read foo; do echo "$foo"; done < <(command here)
    – phemmer
    Jun 28, 2012 at 22:06
  • @Patrick: That's not a pipe, it's redirection. It's process substitution redirected into done. Jun 28, 2012 at 22:35
  • 1
    @Patrick: No, they don't. They do have similarities, but they're different. Jun 28, 2012 at 22:42
  • 2
    the <() construct is essentially a reversed pipe; it's known as process substitution, and uses some other tricks. the noteworthy bit is that it creates a file descriptor (on my system, it tends to be /dev/fd/63) which stores the process's output. that's what makes the redirection work at all. <() itself just spits a filename out. < <() redirects the contents of it, just like < file.
    – Josh McGee
    Jul 23, 2013 at 19:31
3

This is yet another way to assign a variable, good to use with some text editors that are unable to correctly highlight every intricate code you create.

read -r -d '' str < <(cat somefile.txt)
echo "${#str}"
echo "$str"
3
  • Your comment helped with an issue I had, thanks! Nov 29, 2016 at 21:28
  • What can you do with read … < <(cat file.txt) that you can't do with read … < file.txt (which is more portable)? UUOC! Aug 12, 2017 at 17:27
  • @Scott mmm, I learned that way <(), I think it is bash specific? Aug 12, 2017 at 20:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.