Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to read multiline content into variable #1147

Closed
szpak opened this issue Nov 28, 2013 · 14 comments
Closed

Ability to read multiline content into variable #1147

szpak opened this issue Nov 28, 2013 · 14 comments
Milestone

Comments

@szpak
Copy link
Contributor

szpak commented Nov 28, 2013

It would be useful to be able to read multiline input into variable for further usages. For example:

cat myfile | myscript

where in myscript a content of the file is read and passed (for example) to
a clipboard.

In Bash a weird construction like "input="$(< /dev/stdin)" can be used.

@ridiculousfish
Copy link
Member

I wonder if this could be a flag to set, which would tell it to read from stdin.

cat my file | set var -

Perhaps?

@zanchey
Copy link
Member

zanchey commented Nov 29, 2013

We definitely don't want something like bash's syntax!

As you have noted it is possible to use a read loop (while read i; set var $var $i; end) to achieve a similar effect.

Some possibilities:

  • an option to read to set the delimiter and specify EOF as the only delimiter.
  • an option to read to read until EOF.
  • extend set to read the value from STDIN.

Of course, #159 may trip you up...

@szpak
Copy link
Contributor Author

szpak commented Nov 29, 2013

I was worried that read would show me a prompt after the last line from pipe, but in fact it just passes it by. I ended with:

while read i; set var "$var""$i"\n; end
echo $var | head -n -1 > /tmp/foo

(head to remove trailing empty line) which works, but isn't pretty.

- with set uses is similar to already implemented in . (eval). On the other side a flag to read would be related to #1134.

I didn't know about #159, probably this issue could be closed as a duplicate of #159.

@szpak
Copy link
Contributor Author

szpak commented Nov 29, 2013

Ehh, the trailing line was from echo not \n. The following code works fine for "normal" cases.

while read i; set var "$var""$i"\n; end
echo -n $var > /tmp/output

@ridiculousfish ridiculousfish added this to the fish-future milestone Nov 2, 2014
@alphapapa
Copy link

I'm really missing something like Bash's readarray builtin. I'm trying to convert a Bash script to a Fish script, but this is making it nearly impossible. In Bash I would do something like:

readarray -t arrayName <<<"$(grep word file)"

And the result would be an array with each line from grep in an element. Then I could process it like:

for line in "${arrayName[@]}"
do
    echo "Something: $line"
done

Maybe I'm missing something, but I can't find any way to emulate this in Fish, so this is a showstopper. :(

@ridiculousfish
Copy link
Member

@alphapapa Perhaps I'm misunderstanding, but this should just work?

set arrayName (grep word file)
for line in $arrayName
    echo "Something: $line"
end

@alphapapa
Copy link

I'm sorry, I guess it had been a while since I tried using Fish to write a script, and I got confused. I think what confused me was that doing something like this:

set arrayName (grep word file)
echo $arrayname

...removes all of the line breaks, making it appear that it's a single-element variable instead of an array with one line per element.

Is that intended behavior?

Thanks for your patient answer when I probably deserved a "RTM". :)

@faho
Copy link
Member

faho commented Aug 29, 2015

@alphapapa: See #159 - and actually this issue as well.

@szpak
Copy link
Contributor Author

szpak commented Aug 30, 2015

As the topic was already dragged out from the shadow I have a related question. Proposed workaround to put a multiline content from a pipe to a variable:

while read i; set var "$var""$i"\n; end
echo -n $var > /tmp/output

adds unnecessary \n in the situation where the was no empty line at the end on the source content. How can I easily remove only that last character (to simplify the thing it is ok to remove the last \n even if it was in the source content)?

I cannot use set as all line delimiters would be lost.

@zanchey
Copy link
Member

zanchey commented Nov 18, 2015

If you can put the pipe inside a command substitution, you can disable IFS and use this to your advantage:

> set IFS ''; set var (printf 'foo\nbar\n')
> echo $var
foo
bar
> count $var
1

@zanchey
Copy link
Member

zanchey commented Nov 18, 2015

Looking back, I don't think there's anything else to do here.

You can use read in a pipeline with the -z flag to disable splitting on newlines (added in 2.2.0). Alternatively you can use set with command substitutions with IFS set to ''.

So I'm going to close this for now! If you think I've missed something, speak up.

@zanchey zanchey closed this as completed Nov 18, 2015
@zanchey zanchey modified the milestones: next-2.x, fish-future, fish 2.2.0 Nov 18, 2015
@doapp-ryanp
Copy link

For others that run across this, here is a concrete example of what @zanchey is talking about:

cat ./swagger.json | read -z json

@zanchey
Copy link
Member

zanchey commented Apr 13, 2016

You can even do read -z json < swagger.json!

@ElijahLynn
Copy link

Leaving another example here that is very similar to #1147 (comment) but may not be obvious to others. It cats out the file into a list/array.

set arrayName (cat /path/to/file)

e.g.

function curl_codes
  set --local urls (cat $argv)
  for url in $urls
    curl --output /dev/null --silent --head --write-out "%{http_code}\n" $url
    echo " $url"
  end
end

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 17, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants