4
!/bin/bash
VAR=$(some curl commands)
token =$(cut -c 18-53 $VAR)
echo $token

I want to use VAR variable in my cut command but, when I use like this it says;

No such file or directory

I just wanna cut VAR(output of curl command) from 18.char to 53.char. Any suggestion ?

7
  • you can't put space between token and = Commented Nov 21, 2017 at 5:48
  • 2
    Honestly I don't see $VAR being used in cut anywhere Commented Nov 21, 2017 at 5:49
  • 2
    Go to your terminal, type man bash, search for the Parameter Expansion section, then look for ${parameter:offset:length}. This is called "Substring Expansion", and is very well documented. Commented Nov 21, 2017 at 5:53
  • "out" should be "$VAR". When I tried to txt file, I forget Commented Nov 21, 2017 at 6:03
  • The # in #!/bin/bash is significant. Your current shebang would traditionally cause the script file to be executed by csh which is not compatible with Bash. Commented Nov 21, 2017 at 8:24

1 Answer 1

14

Let's define an example var:

$ var='The quick brown fox jumped over the lazy dog on the way to the market'

Now let's select characters 18 through 53 using cut:

$ echo $(cut -c 18-53 <<<"$var")
ox jumped over the lazy dog on the w

Because cut expects to read from standard input (if not a file), we use <<< to tell bash to provide the contents of $var on standard input. This is called a here string.

Alternatively, we can select the same characters using bash alone:

$ echo ${var:17:36}
ox jumped over the lazy dog on the w

The construct ${var:17:36} is called substring expansion. It selects 36 characters starting from position 17. (In bash, unlike cut, the first character is numbered zero.)

We can, of course, assign the selected string to a variable:

$ token=${var:17:36}
$ echo "$token"
ox jumped over the lazy dog on the w

Or:

$ token=$(cut -c 18-53 <<<"$var")
$ echo "$token"
ox jumped over the lazy dog on the w

POSIX

The above commands work in bash. If we want portability to POSIX shells, then we can use neither substring expansion nor here strings. Instead, as Gordon Davisson points out, we can use:

$ echo "$var" | cut -c 18-53
ox jumped over the lazy dog on the w

or:

$ token=$(echo "$var" | cut -c 18-53)
$ echo "$token"
ox jumped over the lazy dog on the w

gniourf_gniourf suggests yet another POSIX method, this one avoiding external processes:

$ printf '%.36s\n' "${var#?????????????????}"
ox jumped over the lazy dog on the w

Comparison of cut and bash substring expansion

As David C. Rankin points out in the comments, there are strong advantages to uses bash's internal string handling. One is that the use of bash's internal commands avoids the spawning of additional subshells and executables. If the additional subshells are spawned within a loop, this can greatly impact performance.

Also, command substitution has the side-effect of removing trailing newlines from its output. This can cause unwanted surprises. Using bash's internal string handling avoids this side-effect.

Sign up to request clarification or add additional context in comments.

7 Comments

The benefit of using string indexes over command substitution and cut is you avoid spawning the additional subshells by using a builtin feature provided by bash. If additional subshells are spawned within a loop, this can greatly impact performance. (@Jon1024 - I know you know, this is just for the OP's benefit)
Just to clarify why the original version didn't work: cut expects its argument to be a filename to read from, not a string to operate on. What John1024's version does it not give it a filename (which cut implicitly treats as meaning to operate on its standard input, rather than a regular file), and then use a "here-string" to pass the string to cut's standard input. The more traditional way to do this is echo "$var" | cut -c 18-53 -- this is even slower, but will work in shells other than bash.
@DavidC.Rankin Good points! Thank you. I've added that to the answer.
@GordonDavisson Also good points! I've added your POSIX version to the answer.
Note that cut works on lines (unless GNU cut is used with the -z option, then works on null-separated fields). So if the variable may contain newlines (and you really want a substring of the full variable), the cut solution is a no-go. A POSIX way could be a combination of printf and parameter expansion: printf '%.36s\n' "${var#?????????????????}" (of course, the long chain of ?'s can be generated programmatically). But you're glad the question is tagged bash!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.