ubuntu:bash:wordsplitting
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
ubuntu:bash:wordsplitting [2019/12/07 02:01] – created peter | ubuntu:bash:wordsplitting [2019/12/07 02:02] (current) – removed peter | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Ubuntu - BASH - WordSplitting ====== | ||
- | |||
- | The shell' | ||
- | |||
- | Understanding how your original command will be transformed by the shell is of paramount importance in writing robust scripts. | ||
- | |||
- | ---- | ||
- | |||
- | From the bash man page: | ||
- | |||
- | The order of expansions is: brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion. | ||
- | |||
- | For additional information on word splitting and argument handling in Bash, consider reading Arguments. | ||
- | |||
- | ---- | ||
- | |||
- | |||
- | ===== What is Word Splitting? ===== | ||
- | |||
- | Let's write a little helper script that will show us the arguments as passed by the shell: | ||
- | |||
- | <code bash> | ||
- | #!/bin/sh - | ||
- | printf "%d args:" " | ||
- | printf " < | ||
- | echo | ||
- | </ | ||
- | |||
- | If you create a file named args with the above contents, make it executable with chmod +x args, and put it in one of the directories listed in echo " | ||
- | |||
- | <code bash> | ||
- | args hello world "how are you?" | ||
- | </ | ||
- | |||
- | returns: | ||
- | |||
- | <code bash> | ||
- | 3 args: < | ||
- | </ | ||
- | |||
- | The ultimate result of most shell commands is to execute some program with a specific set of arguments (as well as setting up environment variables, opening file descriptors, | ||
- | |||
- | Word splitting is part of the process that determines what each of those arguments will be -- after word splitting and pathname expansion, every resulting word becomes an argument to the program that the shell executes. | ||
- | |||
- | Our helper program above receives the argument list as constructed by the shell, and shows it to us. | ||
- | |||
- | Word splitting is performed on the results of almost all unquoted expansions. | ||
- | |||
- | For example: | ||
- | |||
- | <code bash> | ||
- | var=" | ||
- | args $var | ||
- | 4 args: < | ||
- | </ | ||
- | |||
- | ---- | ||
- | |||
- | An example using IFS: | ||
- | |||
- | <code bash> | ||
- | log=/ | ||
- | args $log | ||
- | args: <> <var> <log> < | ||
- | unset IFS | ||
- | </ | ||
- | |||
- | ---- | ||
- | |||
- | An example with CommandSubstitution: | ||
- | |||
- | <code bash> | ||
- | ls -l | ||
- | total 2864 | ||
- | -rw-r--r-- 1 greg greg 2919154 2001-05-23 00:48 Yello - Oh Yeah.mp3 | ||
- | |||
- | args $(ls -l) | ||
- | 11 args: < | ||
- | </ | ||
- | |||
- | ---- | ||
- | |||
- | ===== Controlling Word Splitting ===== | ||
- | |||
- | As you can see above, we usually do not want to let word splitting occur when filenames are involved. (See BashPitfalls for a discussion of this particular issue.) | ||
- | |||
- | Double quoting an expansion suppresses word splitting, except in the special cases of " | ||
- | |||
- | <code bash> | ||
- | var=" | ||
- | 1 args: <This is a variable> | ||
- | |||
- | array=(testing, | ||
- | 3 args: < | ||
- | </ | ||
- | |||
- | " | ||
- | |||
- | There are very complicated rules involving whitespace characters in IFS. Quoting the man page again: | ||
- | |||
- | * If IFS is unset, or its value is exactly < | ||
- | * If IFS has a value other than the default, then sequences of the whitespace characters space and tab are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character). | ||
- | * Any character in IFS that is not IFS whitespace, along with any adjacent IFS whitespace characters, delimits a field. | ||
- | * A sequence of IFS whitespace characters is also treated as a delimiter. | ||
- | * If the value of IFS is null, no word splitting occurs. | ||
- | |||
- | We won't explore those rules in depth here, except to note the part about sequences of non-whitespace characters. | ||
- | |||
- | If IFS contains non-whitespace characters, then empty words can be generated: | ||
- | |||
- | <code bash> | ||
- | getent passwd sshd | ||
- | sshd: | ||
- | |||
- | IFS=:; args $(getent passwd sshd) | ||
- | 7 args: < | ||
- | |||
- | unset IFS | ||
- | </ | ||
- | |||
- | There was another empty word generated in one of our previous examples, where IFS was set to /. The observant reader will have noticed, therefore, that non-whitespace IFS characters are not ignored at the beginning and end of expansions, the way whitespace IFS characters are. | ||
- | |||
- | Whitespace IFS characters get consolidated. | ||
- | |||
- | Finally, we note that pathname expansion happens after word splitting, and can produce some very shocking results. | ||
- | |||
- | <code bash> | ||
- | getent passwd qmaild | ||
- | qmaild: | ||
- | |||
- | IFS=:; args $(getent passwd qmaild) | ||
- | 737 args: < | ||
- | |||
- | unset IFS | ||
- | </ | ||
- | |||
- | The * word, produced by the shell' | ||
- | |||
- | <code bash> | ||
- | files=' | ||
- | args $files | ||
- | 2 args: <Yello - Oh Yeah.mp3> | ||
- | </ | ||
- | |||
- | Pathname expansion can be disabled with set -f or set -o noglob; though this can lead to surprising and confusing code. | ||
- | |||
- | ---- | ||
- | |||
- | ===== Notes ===== | ||
- | |||
- | * Word splitting is not performed on expansions inside Bash keywords such as [[ ... ]] and case. | ||
- | * Word splitting is not performed on expansions in assignments. Thus, one does not need to quote anything in a command like these: | ||
- | |||
- | * foo=$bar | ||
- | |||
- | * bar=$(a command) | ||
- | |||
- | * logfile=$logdir/ | ||
- | |||
- | * PATH=/ | ||
- | |||
- | * In either case, quoting anyway will not break anything. So if in doubt, quote! | ||
- | |||
- | * When using the read command (which you generally don't want to use without -r), word splitting is performed on the input. | ||
- | |||
ubuntu/bash/wordsplitting.1575684088.txt.gz · Last modified: 2020/07/15 09:30 (external edit)