How to split a string into an array in Bash? (2012)
stackoverflow.com
stackoverflow.com
Everything is basically either a formatted input or a formatted output at the end of the day. Trying to shoehorn things into data "structures" that enable efficient access in certain cases rarely makes sense because of all the processing you need to do to get it there in the first place and it winds up being more efficient just deal in formatted streams of data even if you need to deal with some ugly nested loops and function calls to do it.
We did a bunch of stuff with “xargs”. He said it was the one misunderstood command. One of the cool things was the ability to parallelize the work with a simple -P flag.
You do a find, make sure to use the -print0 flag, pipe it into xargs and use the -0 option then run a command over all the files. If you add -P it magically becomes parallel.
I spend half my time trying to find the right arguments and the whole time wishing I just bit the bullet at the start and used a real programming language.
And god forbid if a filename might have a quote character or a space in it. Then you have to think 5x as hard about what you're doing.
Honestly I'm flabbergasted that stackoverflow is willing to engage in such unethical, immoral behavior on their very first customer-facing interaction.
When I use a browser with blockers, the experience is better.
The frequency just serves as a helpful reminder of this significant taint on their ethics.
It makes me wonder about the people that work at stackexchange.
Regarding the multiple ways though, I think it's a matter of good judgment. Depending on the input, one may choose different tools - one should not forget that Bash is a glue language, intended to make tools work together.
Declarative languages, like SQL or (dare I say) Terraform, seem to be good teaching tools in that regard.
Bash is tiny, flexible, and highly effective at what it was designed to do: shell scripting, which is effectively user OS commandline automation.
It would be akin to me complaining that my microwave doesn't actually prepare a dinner for me, it just heats things up.
Oh, boy. Let me tell you about CSS.
Needed to build a custom R Shiny server with CI/CD, typical build and deploy. I start writing the initial install script which is in Bash.
I didn't take a step back when I started writing the CI/CD or the customised tooling to automate the deployment.
Now I'm a thousand lines deep across two pipelines and I'm equal parts impressed and terrified of the bash monster I've created.
If the script is simple enough it might be worth learning and implementing a bash script than trying to test if Python is installed and the right version etc.
But I would love a shell with a sane language. At the moment I am using zsh + oh-my-zsh because I can not let go of the autocompletion I get. I tried some other shells like oil shell, ion shell, nushell and elvish but sadly the completion is just not there yet. The only shell with maybe even better completions I came a cross is fish, but I don't love the language, while it seems better than sh/bash to me I'd much rather have something more similar to ion shell with stronger typing.
Thinking about command completion, this seems like the analog problem to editors and the language server protocol. Is there something like a command completion server?
My personal flip point is error handling. If errors aren't important, shell. If they are, shell with `set -e`. If errors are important but also shouldn't immediately kill the script from one failure, Python.
Doesn't everyone :) Piping typed objects instead of text (notably Powershell) solves quite some general bash issue, unfortunately Powershell isn't exactly a sane language.
$ string="Los Angeles, London, Belfast, New York"
$ IFS="," read -r -a array <<< "${string/, /,}"
$ echo ${array[0]}
Los Angeles
$ echo ${array[1]}
London
..etc.Don't have the free time today to read the rest of it unfortunately.
I would worry about making it correct before making it fast, the former being a big challenge!
Shells Use Temp Files to Implement Here Documents : http://www.oilshell.org/blog/2016/10/18.html
(Oil doesn't do this; it creates a process for here docs without touching disk. In theory this could be eliminated for here docs less than PIPE_BUF, which is probably a lot of them)
Here's a version that doesn't use "here string" and so doesn't create temporary files.
#!/bin/bash
shopt -s lastpipe
string="Los Angeles, London, Belfast, New York"
echo "${string/, /,}" | readarray -d, -t arrayA
echo ${arrayA[0]}
echo ${arrayA[1]}
Also, the lastpipe option runs the readarray in the context of the current process.The specification is: "speed does not matter".
The long answer addresses this solution:
$ string="Los Angeles, London, Belfast, New York"
$ IFS="," read -r -a array <<< "${string/, /,}"
$ echo ${array[0]}
Los Angeles
$ echo ${array[1]}
London
as "not very generic" in point #3, which is correct. Bash simply doesn't support generic splitting by itself (things go downhill quickly once, for example, newlines are introduced, and so on), and if precision/flexibility are priority over speed, then it's better to use standard linux tools. python -c 'print sys.stdin.read().split(", ")'
Or you can use sed and use read -d $'\x01': echo -n "$mystr" | sed $'s/, /\x01/
That will handle newlines but not the 0x01 byte.I think really a shell should have the ability to iterate over bytes/code points reasonably efficiently to do arbitrary string processing. Python isn't great at this either, since it creates a lot of 1 byte string objects.
> set array (string split ", " $string)
Afterwards you can also use the fact that arrays and array elements act far more predictably in fish (no implicit splitting on whitespace, for example).
$ echo {one,two,three}{A,B,C}{0,1,2,3,4}
oneA0 oneA1 oneA2 oneA3 oneA4 oneB0 oneB1 oneB2 oneB3 oneB4 oneC0 oneC1 oneC2 oneC3 oneC4 twoA0 twoA1 twoA2 twoA3 twoA4 twoB0 twoB1 twoB2 twoB3 twoB4 twoC0 twoC1 twoC2 twoC3 twoC4 threeA0 threeA1 threeA2 threeA3 threeA4 threeB0 threeB1 threeB2 threeB3 threeB4 threeC0 threeC1 threeC2 threeC3 threeC4 echo {one,two,three}{A..C}{0..4}Fish has "string split":
$ string split ", " "Paris, France, Europe"
Paris
France
Europe
Murex has "jsplit": » echo "Paris, France, Europe" -> jsplit ", "
[
"Paris",
"France",
"Europe"
]
But neither are really Bash compatible. Is zsh any better? $ print -l ${(s:, :):-Paris, France, Europe}
Paris
France
Europe
I won't try to answer the "is zsh any better?" question with this response either ;) string="Paris, France, Europe"
arr=(${(s:, :)string})
for x in $arr; do echo "<$x>"; done
<Paris>
<France>
<Europe>> set -f
And why does `set` use a flag with no argument after it? It's simple, just follow the rules:
Single dash for single letter flags
Double dash for full word flags
No dash for flag arguments
No dash for some non-flag arguments from ancient commands
Sometimes the dash is a "minus" prefix and has a matching "plus" prefix for a non-flag argument
Gang them all together sometimes
Git uses lots of subcommands and flags, often in surprising combinations
Not always can you gang together single letter flags
? Can you always gang together single letter flags? I'm not really sure TBH
Never gang together full word flags.
The short pneumonic "SDNNSGGN?N" is instructive here. The trouble you'll have remembering that pneumonic will remind you how much of a pain bash is.
Virtually any problem of "how do I do X in bash?" is solved trivially by Awk. If you don't know Awk, then any number of tools cobbled together in an inefficient, janky Bash function will get the job done so you can get on with your day.
If you need something robust, use an actual programming language, as "robust" things already need significant investment in development, testing, and maintenance.