mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-12 04:58:57 +00:00
Remove IFS support
This has been officially deprecated for a long, long time.
This commit is contained in:
parent
95f4c9c07e
commit
ee19759da1
8 changed files with 16 additions and 113 deletions
|
@ -84,7 +84,7 @@ The following options control how much is read and how it is stored:
|
||||||
Makes ``read`` return after reading *NCHARS* characters or the end of the line, whichever comes first.
|
Makes ``read`` return after reading *NCHARS* characters or the end of the line, whichever comes first.
|
||||||
|
|
||||||
**-t** -or **--tokenize**
|
**-t** -or **--tokenize**
|
||||||
Causes read to split the input into variables by the shell's tokenization rules. This means it will honor quotes and escaping. This option is of course incompatible with other options to control splitting like **--delimiter** and does not honor :envvar:`IFS` (like fish's tokenizer). It saves the tokens in the manner they'd be passed to commands on the commandline, so e.g. ``a\ b`` is stored as ``a b``. Note that currently it leaves command substitutions intact along with the parentheses.
|
Causes read to split the input into variables by the shell's tokenization rules. This means it will honor quotes and escaping. This option is of course incompatible with other options to control splitting like **--delimiter**. It saves the tokens in the manner they'd be passed to commands on the commandline, so e.g. ``a\ b`` is stored as ``a b``. Note that currently it leaves command substitutions intact along with the parentheses.
|
||||||
|
|
||||||
**-a** or **--list**
|
**-a** or **--list**
|
||||||
Stores the result as a list in a single variable. This option is also available as **--array** for backwards compatibility.
|
Stores the result as a list in a single variable. This option is also available as **--array** for backwards compatibility.
|
||||||
|
@ -97,7 +97,7 @@ The following options control how much is read and how it is stored:
|
||||||
|
|
||||||
Without the ``--line`` option, ``read`` reads a single line of input from standard input, breaks it into tokens, and then assigns one token to each variable specified in *VARIABLES*. If there are more tokens than variables, the complete remainder is assigned to the last variable.
|
Without the ``--line`` option, ``read`` reads a single line of input from standard input, breaks it into tokens, and then assigns one token to each variable specified in *VARIABLES*. If there are more tokens than variables, the complete remainder is assigned to the last variable.
|
||||||
|
|
||||||
If no option to determine how to split like ``--delimiter``, ``--line`` or ``--tokenize`` is given, the variable ``IFS`` is used as a list of characters to split on. Relying on the use of ``IFS`` is deprecated and this behaviour will be removed in future versions. The default value of ``IFS`` contains space, tab and newline characters. As a special case, if ``IFS`` is set to the empty string, each character of the input is considered a separate token.
|
If no option to determine how to split like ``--delimiter``, ``--line`` or ``--tokenize`` is given, the default fish behavior of splitting output on space, tab, and new-line characters is used.
|
||||||
|
|
||||||
With the ``--line`` option, ``read`` reads a line of input from standard input into each provided variable, stopping when each variable has been filled. The line is not tokenized.
|
With the ``--line`` option, ``read`` reads a line of input from standard input into each provided variable, stopping when each variable has been filled. The line is not tokenized.
|
||||||
|
|
||||||
|
|
|
@ -827,7 +827,7 @@ A ``command substitution`` is an expansion that uses the *output* of a command a
|
||||||
|
|
||||||
This executes the :doc:`pwd <cmds/pwd>` command, takes its output (more specifically what it wrote to the standard output "stdout" stream) and uses it as arguments to :doc:`echo <cmds/echo>`. So the inner command (the ``pwd``) is run first and has to complete before the outer command can even be started.
|
This executes the :doc:`pwd <cmds/pwd>` command, takes its output (more specifically what it wrote to the standard output "stdout" stream) and uses it as arguments to :doc:`echo <cmds/echo>`. So the inner command (the ``pwd``) is run first and has to complete before the outer command can even be started.
|
||||||
|
|
||||||
If the inner command prints multiple lines, fish will use each separate line as a separate argument to the outer command. Unlike other shells, the value of ``$IFS`` is not used [#]_, fish splits on newlines.
|
If the inner command prints multiple lines, fish will use each separate line as a separate argument to the outer command. Unlike other shells, the value of ``$IFS`` is not used, fish splits on newlines.
|
||||||
|
|
||||||
Command substitutions can also be double-quoted::
|
Command substitutions can also be double-quoted::
|
||||||
|
|
||||||
|
@ -872,8 +872,6 @@ This creates a temporary file, stores the output of the command in that file and
|
||||||
|
|
||||||
Fish has a default limit of 100 MiB on the data it will read in a command sustitution. If that limit is reached the command (all of it, not just the command substitution - the outer command won't be executed at all) fails and ``$status`` is set to 122. This is so command substitutions can't cause the system to go out of memory, because typically your operating system has a much lower limit, so reading more than that would be useless and harmful. This limit can be adjusted with the ``fish_read_limit`` variable (`0` meaning no limit). This limit also affects the :doc:`read <cmds/read>` command.
|
Fish has a default limit of 100 MiB on the data it will read in a command sustitution. If that limit is reached the command (all of it, not just the command substitution - the outer command won't be executed at all) fails and ``$status`` is set to 122. This is so command substitutions can't cause the system to go out of memory, because typically your operating system has a much lower limit, so reading more than that would be useless and harmful. This limit can be adjusted with the ``fish_read_limit`` variable (`0` meaning no limit). This limit also affects the :doc:`read <cmds/read>` command.
|
||||||
|
|
||||||
.. [#] One exception: Setting ``$IFS`` to empty will disable line splitting. This is deprecated, use :doc:`string split <cmds/string-split>` instead.
|
|
||||||
|
|
||||||
.. _expand-brace:
|
.. _expand-brace:
|
||||||
|
|
||||||
Brace expansion
|
Brace expansion
|
||||||
|
@ -1697,10 +1695,6 @@ Fish also provides additional information through the values of certain environm
|
||||||
|
|
||||||
the machine's hostname.
|
the machine's hostname.
|
||||||
|
|
||||||
.. ENVVAR:: IFS
|
|
||||||
|
|
||||||
the internal field separator that is used for word splitting with the :doc:`read <cmds/read>` builtin. Setting this to the empty string will also disable line splitting in :ref:`command substitution <expand-command-substitution>`. This variable can be changed.
|
|
||||||
|
|
||||||
.. envvar:: last_pid
|
.. envvar:: last_pid
|
||||||
|
|
||||||
the process ID (PID) of the last background process.
|
the process ID (PID) of the last background process.
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#
|
#
|
||||||
# Set default field separators
|
# Set default field separators
|
||||||
#
|
#
|
||||||
set -g IFS \n\ \t
|
|
||||||
set -qg __fish_added_user_paths
|
set -qg __fish_added_user_paths
|
||||||
or set -g __fish_added_user_paths
|
or set -g __fish_added_user_paths
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ use crate::common::unescape_string;
|
||||||
use crate::common::valid_var_name;
|
use crate::common::valid_var_name;
|
||||||
use crate::common::UnescapeStringStyle;
|
use crate::common::UnescapeStringStyle;
|
||||||
use crate::env::EnvMode;
|
use crate::env::EnvMode;
|
||||||
use crate::env::Environment;
|
|
||||||
use crate::env::READ_BYTE_LIMIT;
|
use crate::env::READ_BYTE_LIMIT;
|
||||||
use crate::env::{EnvVar, EnvVarFlags};
|
use crate::env::{EnvVar, EnvVarFlags};
|
||||||
use crate::input_common::terminal_protocols_disable_ifn;
|
use crate::input_common::terminal_protocols_disable_ifn;
|
||||||
|
@ -30,6 +29,9 @@ use libc::SEEK_CUR;
|
||||||
use std::os::fd::RawFd;
|
use std::os::fd::RawFd;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
/// Fish's hard-coded set of default output delimiters
|
||||||
|
const IFS: &wstr = L!(" \n\t");
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Options {
|
struct Options {
|
||||||
print_help: bool,
|
print_help: bool,
|
||||||
|
@ -689,12 +691,9 @@ pub fn read(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
||||||
// todo!("don't clone")
|
// todo!("don't clone")
|
||||||
let delimiter = opts
|
let delimiter = opts
|
||||||
.delimiter
|
.delimiter
|
||||||
.clone()
|
.as_ref()
|
||||||
.or_else(|| {
|
.map(|delim| delim.as_utfstr())
|
||||||
let ifs = parser.vars().get_unless_empty(L!("IFS"));
|
.unwrap_or(IFS);
|
||||||
ifs.map(|ifs| ifs.as_string())
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
if delimiter.is_empty() {
|
if delimiter.is_empty() {
|
||||||
// Every character is a separate token with one wrinkle involving non-array mode where
|
// Every character is a separate token with one wrinkle involving non-array mode where
|
||||||
|
|
3
src/env/environment.rs
vendored
3
src/env/environment.rs
vendored
|
@ -694,9 +694,6 @@ pub fn env_init(paths: Option<&ConfigPaths>, do_uvars: bool, default_paths: bool
|
||||||
// Set up a default PATH
|
// Set up a default PATH
|
||||||
setup_path();
|
setup_path();
|
||||||
|
|
||||||
// Set up $IFS - this used to be in share/config.fish, but really breaks if it isn't done.
|
|
||||||
vars.set_one(L!("IFS"), EnvMode::GLOBAL, "\n \t".into());
|
|
||||||
|
|
||||||
// Ensure this var is present even before an interactive command is run so that if it is used
|
// Ensure this var is present even before an interactive command is run so that if it is used
|
||||||
// in a function like `fish_prompt` or `fish_right_prompt` it is defined at the time the first
|
// in a function like `fish_prompt` or `fish_right_prompt` it is defined at the time the first
|
||||||
// prompt is written.
|
// prompt is written.
|
||||||
|
|
|
@ -1472,7 +1472,8 @@ fn exec_subshell_internal(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let split_output = parser.vars().get_unless_empty(L!("IFS")).is_some();
|
// Holdover from when we checked for an empty $IFS
|
||||||
|
let split_output = true;
|
||||||
|
|
||||||
// IO buffer creation may fail (e.g. if we have too many open files to make a pipe), so this may
|
// IO buffer creation may fail (e.g. if we have too many open files to make a pipe), so this may
|
||||||
// be null.
|
// be null.
|
||||||
|
|
|
@ -37,11 +37,10 @@ use std::sync::{Arc, Condvar, Mutex, MutexGuard};
|
||||||
/// produce a stream of bytes, and those get stored directly. However other commands produce
|
/// produce a stream of bytes, and those get stored directly. However other commands produce
|
||||||
/// explicitly separated output, in particular `string` like `string collect` and `string split0`.
|
/// explicitly separated output, in particular `string` like `string collect` and `string split0`.
|
||||||
/// The buffer tracks a sequence of elements. Some elements are explicitly separated and should not
|
/// The buffer tracks a sequence of elements. Some elements are explicitly separated and should not
|
||||||
/// be further split; other elements have inferred separation and may be split by IFS (or not,
|
/// be further split; other elements have inferred separation.
|
||||||
/// depending on its value).
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum SeparationType {
|
pub enum SeparationType {
|
||||||
/// this element should be further separated by IFS
|
/// this element should be further separated according to default behavior
|
||||||
inferred,
|
inferred,
|
||||||
/// this element is explicitly separated and should not be further split
|
/// this element is explicitly separated and should not be further split
|
||||||
explicitly,
|
explicitly,
|
||||||
|
@ -65,7 +64,7 @@ impl BufferElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A separated_buffer_t contains a list of elements, some of which may be separated explicitly and
|
/// A separated_buffer_t contains a list of elements, some of which may be separated explicitly and
|
||||||
/// others which must be separated further by the user (e.g. via IFS).
|
/// others which must be separated further by the user.
|
||||||
pub struct SeparatedBuffer {
|
pub struct SeparatedBuffer {
|
||||||
/// Limit on how much data we'll buffer. Zero means no limit.
|
/// Limit on how much data we'll buffer. Zero means no limit.
|
||||||
buffer_limit: usize,
|
buffer_limit: usize,
|
||||||
|
|
|
@ -11,35 +11,8 @@ read --array v1 v2
|
||||||
#CHECKERR: read: expected 1 arguments; got 2
|
#CHECKERR: read: expected 1 arguments; got 2
|
||||||
read --list v1
|
read --list v1
|
||||||
|
|
||||||
# Verify correct behavior of subcommands and splitting of input.
|
|
||||||
begin
|
|
||||||
count (echo one\ntwo)
|
|
||||||
#CHECK: 2
|
|
||||||
set -l IFS \t
|
|
||||||
count (echo one\ntwo)
|
|
||||||
#CHECK: 2
|
|
||||||
set -l IFS
|
|
||||||
count (echo one\ntwo)
|
|
||||||
#CHECK: 1
|
|
||||||
echo [(echo -n one\ntwo)]
|
|
||||||
#CHECK: [one
|
|
||||||
#CHECK: two]
|
|
||||||
count (echo one\ntwo\n)
|
|
||||||
#CHECK: 1
|
|
||||||
echo [(echo -n one\ntwo\n)]
|
|
||||||
#CHECK: [one
|
|
||||||
#CHECK: two]
|
|
||||||
count (echo one\ntwo\n\n)
|
|
||||||
#CHECK: 1
|
|
||||||
echo [(echo -n one\ntwo\n\n)]
|
|
||||||
#CHECK: [one
|
|
||||||
#CHECK: two
|
|
||||||
#CHECK: ]
|
|
||||||
end
|
|
||||||
|
|
||||||
function print_vars --no-scope-shadowing
|
function print_vars --no-scope-shadowing
|
||||||
set -l space
|
set -l space
|
||||||
set -l IFS \n # ensure our command substitution works right
|
|
||||||
for var in $argv
|
for var in $argv
|
||||||
echo -n $space (count $$var) \'$$var\'
|
echo -n $space (count $$var) \'$$var\'
|
||||||
set space ''
|
set space ''
|
||||||
|
@ -70,31 +43,6 @@ echo -n a | read -l one
|
||||||
echo "$status $one"
|
echo "$status $one"
|
||||||
#CHECK: 0 a
|
#CHECK: 0 a
|
||||||
|
|
||||||
# Test splitting input with IFS empty
|
|
||||||
set -l IFS
|
|
||||||
echo hello | read -l one
|
|
||||||
print_vars one
|
|
||||||
#CHECK: 1 'hello'
|
|
||||||
echo hello | read -l one two
|
|
||||||
print_vars one two
|
|
||||||
#CHECK: 1 'h' 1 'ello'
|
|
||||||
echo hello | read -l one two three
|
|
||||||
print_vars one two three
|
|
||||||
#CHECK: 1 'h' 1 'e' 1 'llo'
|
|
||||||
echo '' | read -l one
|
|
||||||
print_vars one
|
|
||||||
#CHECK: 0
|
|
||||||
echo t | read -l one two
|
|
||||||
print_vars one two
|
|
||||||
#CHECK: 1 't' 0
|
|
||||||
echo t | read -l one two three
|
|
||||||
print_vars one two three
|
|
||||||
#CHECK: 1 't' 0 0
|
|
||||||
echo ' t' | read -l one two
|
|
||||||
print_vars one two
|
|
||||||
#CHECK: 1 ' ' 1 't'
|
|
||||||
set -le IFS
|
|
||||||
|
|
||||||
echo 'hello there' | read -la ary
|
echo 'hello there' | read -la ary
|
||||||
print_vars ary
|
print_vars ary
|
||||||
#CHECK: 2 'hello' 'there'
|
#CHECK: 2 'hello' 'there'
|
||||||
|
@ -111,18 +59,6 @@ echo '' | read -la ary
|
||||||
print_vars ary
|
print_vars ary
|
||||||
#CHECK: 0
|
#CHECK: 0
|
||||||
|
|
||||||
set -l IFS
|
|
||||||
echo hello | read -la ary
|
|
||||||
print_vars ary
|
|
||||||
#CHECK: 5 'h' 'e' 'l' 'l' 'o'
|
|
||||||
echo h | read -la ary
|
|
||||||
print_vars ary
|
|
||||||
#CHECK: 1 'h'
|
|
||||||
echo '' | read -la ary
|
|
||||||
print_vars ary
|
|
||||||
#CHECK: 0
|
|
||||||
set -le IFS
|
|
||||||
|
|
||||||
# read -n tests
|
# read -n tests
|
||||||
echo testing | read -n 3 foo
|
echo testing | read -n 3 foo
|
||||||
echo $foo
|
echo $foo
|
||||||
|
@ -254,7 +190,7 @@ echo abc\ndef | $fish -i -c 'read a; read b; set --show a; set --show b' | $filt
|
||||||
#CHECK: $b: set in global scope, unexported, with 1 elements
|
#CHECK: $b: set in global scope, unexported, with 1 elements
|
||||||
#CHECK: $b[1]: |def|
|
#CHECK: $b[1]: |def|
|
||||||
|
|
||||||
# Test --delimiter (and $IFS, for now)
|
# Test --delimiter
|
||||||
echo a=b | read -l foo bar
|
echo a=b | read -l foo bar
|
||||||
echo $foo
|
echo $foo
|
||||||
echo $bar
|
echo $bar
|
||||||
|
@ -276,18 +212,7 @@ echo $bar
|
||||||
echo $baz
|
echo $baz
|
||||||
#CHECK: b
|
#CHECK: b
|
||||||
|
|
||||||
# IFS empty string
|
# Default behavior
|
||||||
set -l IFS ''
|
|
||||||
echo a=b | read -l foo bar baz
|
|
||||||
echo $foo
|
|
||||||
#CHECK: a
|
|
||||||
echo $bar
|
|
||||||
#CHECK: =
|
|
||||||
echo $baz
|
|
||||||
#CHECK: b
|
|
||||||
|
|
||||||
# IFS unset
|
|
||||||
set -e IFS
|
|
||||||
echo a=b | read -l foo bar baz
|
echo a=b | read -l foo bar baz
|
||||||
echo $foo
|
echo $foo
|
||||||
#CHECK: a=b
|
#CHECK: a=b
|
||||||
|
@ -313,17 +238,6 @@ echo $b
|
||||||
#CHECK: b
|
#CHECK: b
|
||||||
echo $c
|
echo $c
|
||||||
#CHECK: c
|
#CHECK: c
|
||||||
# Multi-char delimiters with IFS
|
|
||||||
begin
|
|
||||||
set -l IFS "..."
|
|
||||||
echo a...b...c | read -l a b c
|
|
||||||
echo $a
|
|
||||||
echo $b
|
|
||||||
echo $c
|
|
||||||
end
|
|
||||||
#CHECK: a
|
|
||||||
#CHECK: b
|
|
||||||
#CHECK: ..c
|
|
||||||
|
|
||||||
# At one point, whatever was read was printed _before_ banana
|
# At one point, whatever was read was printed _before_ banana
|
||||||
echo banana (echo sausage | read)
|
echo banana (echo sausage | read)
|
||||||
|
|
Loading…
Reference in a new issue