Remove IFS support

This has been officially deprecated for a long, long time.
This commit is contained in:
Mahmoud Al-Qudsi 2024-11-10 13:01:38 -06:00
parent 95f4c9c07e
commit ee19759da1
8 changed files with 16 additions and 113 deletions

View file

@ -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.
**-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**
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.
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.

View file

@ -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.
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::
@ -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.
.. [#] One exception: Setting ``$IFS`` to empty will disable line splitting. This is deprecated, use :doc:`string split <cmds/string-split>` instead.
.. _expand-brace:
Brace expansion
@ -1697,10 +1695,6 @@ Fish also provides additional information through the values of certain environm
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
the process ID (PID) of the last background process.

View file

@ -3,7 +3,6 @@
#
# Set default field separators
#
set -g IFS \n\ \t
set -qg __fish_added_user_paths
or set -g __fish_added_user_paths

View file

@ -9,7 +9,6 @@ use crate::common::unescape_string;
use crate::common::valid_var_name;
use crate::common::UnescapeStringStyle;
use crate::env::EnvMode;
use crate::env::Environment;
use crate::env::READ_BYTE_LIMIT;
use crate::env::{EnvVar, EnvVarFlags};
use crate::input_common::terminal_protocols_disable_ifn;
@ -30,6 +29,9 @@ use libc::SEEK_CUR;
use std::os::fd::RawFd;
use std::sync::atomic::Ordering;
/// Fish's hard-coded set of default output delimiters
const IFS: &wstr = L!(" \n\t");
#[derive(Default)]
struct Options {
print_help: bool,
@ -689,12 +691,9 @@ pub fn read(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
// todo!("don't clone")
let delimiter = opts
.delimiter
.clone()
.or_else(|| {
let ifs = parser.vars().get_unless_empty(L!("IFS"));
ifs.map(|ifs| ifs.as_string())
})
.unwrap_or_default();
.as_ref()
.map(|delim| delim.as_utfstr())
.unwrap_or(IFS);
if delimiter.is_empty() {
// Every character is a separate token with one wrinkle involving non-array mode where

View file

@ -694,9 +694,6 @@ pub fn env_init(paths: Option<&ConfigPaths>, do_uvars: bool, default_paths: bool
// Set up a default 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
// in a function like `fish_prompt` or `fish_right_prompt` it is defined at the time the first
// prompt is written.

View file

@ -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
// be null.

View file

@ -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
/// 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
/// be further split; other elements have inferred separation and may be split by IFS (or not,
/// depending on its value).
/// be further split; other elements have inferred separation.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum SeparationType {
/// this element should be further separated by IFS
/// this element should be further separated according to default behavior
inferred,
/// this element is explicitly separated and should not be further split
explicitly,
@ -65,7 +64,7 @@ impl BufferElement {
}
/// 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 {
/// Limit on how much data we'll buffer. Zero means no limit.
buffer_limit: usize,

View file

@ -11,35 +11,8 @@ read --array v1 v2
#CHECKERR: read: expected 1 arguments; got 2
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
set -l space
set -l IFS \n # ensure our command substitution works right
for var in $argv
echo -n $space (count $$var) \'$$var\'
set space ''
@ -70,31 +43,6 @@ echo -n a | read -l one
echo "$status $one"
#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
print_vars ary
#CHECK: 2 'hello' 'there'
@ -111,18 +59,6 @@ echo '' | read -la ary
print_vars ary
#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
echo testing | read -n 3 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[1]: |def|
# Test --delimiter (and $IFS, for now)
# Test --delimiter
echo a=b | read -l foo bar
echo $foo
echo $bar
@ -276,18 +212,7 @@ echo $bar
echo $baz
#CHECK: b
# IFS empty string
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
# Default behavior
echo a=b | read -l foo bar baz
echo $foo
#CHECK: a=b
@ -313,17 +238,6 @@ echo $b
#CHECK: b
echo $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
echo banana (echo sausage | read)