diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a5026dfc034..dff71d07e23 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1560,6 +1560,7 @@ show you the alternatives available, if there is more than one possibility).
 
 @menu
 * Command Syntax::              How to give commands to @value{GDBN}
+* Command Settings::            How to change default behavior of commands
 * Completion::                  Command completion
 * Command Options::             Command options
 * Help::                        How to ask @value{GDBN} for help
@@ -1616,6 +1617,92 @@ commands.  This command accepts the current line, like @key{RET}, and
 then fetches the next line relative to the current line from the history
 for editing.
 
+
+@node Command Settings
+@section Command Settings
+@cindex change default behavior of commands
+@cindex change default settings
+
+Many commands change their behavior according to command-specific
+variables or settings.  These settings can be changed with the
+@code{set} subcommands.  For example, the @code{print} command
+(@pxref{Data, ,Examining Data}) prints arrays differently depending on
+settings changeable with the commands @code{set print elements
+NUMBER-OF-ELEMENTS} and @code{set print array-indexes}, among others.
+
+You can set these settings to your preference in the gdbinit files
+loaded at @value{GDBN} startup.  @xref{Startup}.
+
+The settings can also be changed interactively during the debugging
+session.  For example, to change the limit of array elements to print,
+you can do the following:
+@smallexample
+(@value{GDBN}) set print elements 10
+(@value{GDBN}) print some_array
+$1 = @{0, 10, 20, 30, 40, 50, 60, 70, 80, 90...@}
+@end smallexample
+
+The above @code{set print elements 10} command changes the number of
+elements to print from the default of 200 to 10.  If you only intend
+this limit of 10 to be used for printing @code{some_array}, then you
+must restore the limit back to 200, with @code{set print elements
+200}.
+
+Some commands allow overriding settings with command options.  For
+example, the @code{print} command supports a number of options that
+allow overriding relevant global print settings as set by @code{set
+print} subcommands.  @xref{print options}.  The example above could be
+rewritten as:
+@smallexample
+(@value{GDBN}) print -elements 10 -- some_array
+$1 = @{0, 10, 20, 30, 40, 50, 60, 70, 80, 90...@}
+@end smallexample
+
+Alternatively, you can use the @code{with} command to change a setting
+temporarily, for the duration of a command invocation.
+
+@table @code
+@kindex with command
+@kindex w @r{(@code{with})}
+@cindex settings
+@cindex temporarily change settings
+@item with @var{setting} [@var{value}] [-- @var{command}]
+@itemx w @var{setting} [@var{value}] [-- @var{command}]
+Temporarily set @var{setting} to @var{value} for the duration of
+@var{command}.
+
+If no @var{command} is provided, the last command executed is
+repeated.
+
+@var{setting} is any setting settable with the @code{set} subcommands.
+
+For example, the command
+@smallexample
+(@value{GDBN}) with print array on -- print some_array
+@end smallexample
+@noindent
+is equivalent to the following 3 commands:
+@smallexample
+(@value{GDBN}) set print array on
+(@value{GDBN}) print some_array
+(@value{GDBN}) set print array off
+@end smallexample
+
+The @code{with} command is particularly useful when you want to
+override a setting while running user-defined commands, or commands
+defined in Python or Guile.  @xref{Extending GDB,, Extending GDB}.
+
+@smallexample
+(@value{GDBN}) with print pretty on -- my_complex_command
+@end smallexample
+
+To change several settings for the same command, you can nest
+@code{with} commands.  For example, @code{with language ada -- with
+print elements 10} temporarily changes the language to Ada and sets a
+limit of 10 elements to print for arrays and strings.
+
+@end table
+
 @node Completion
 @section Command Completion
 
diff --git a/gdb/NEWS b/gdb/NEWS
index 8718c400d1e..dd993481af8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,6 +46,18 @@ pipe -d DELIM COMMAND DELIM SHELL_COMMAND
   With no COMMAND, repeat the last executed command
   and send its output to SHELL_COMMAND.
 
+with SETTING [VALUE] [-- COMMAND]
+w SETTING [VALUE] [-- COMMAND]
+  Temporarily set SETTING, run COMMAND, and restore SETTING.
+  Usage: with SETTING -- COMMAND
+  With no COMMAND, repeats the last executed command.
+  SETTING is any GDB setting settable with the "set" command.
+  For example, 'with language c -- print someobj' temporarily switches
+  to the C language in order to print someobj.  Settings can be
+  combined: 'w lang c -- w print elements unlimited -- usercmd'
+  switches to the C language and runs usercmd with no limit on array
+  elements to print.
+
 set may-call-functions [on|off]
 show may-call-functions
   This controls whether GDB will attempt to call functions in
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 62f4d7f0c5e..05aa9525b02 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -878,12 +878,7 @@ pipe_command (const char *arg, int from_tty)
   arg += delim.length (); /* Skip the delimiter.  */
 
   if (gdb_cmd.empty ())
-    {
-      repeat_previous ();
-      gdb_cmd = skip_spaces (get_saved_command_line ());
-      if (gdb_cmd.empty ())
-	error (_("No previous command to relaunch"));
-    }
+    gdb_cmd = repeat_previous ();
 
   const char *shell_command = skip_spaces (arg);
   if (*shell_command == '\0')
diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index 8199fa7c0b0..91170627b3d 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -190,7 +190,7 @@ parse_cli_var_uinteger (var_types var_type, const char **arg,
 {
   LONGEST val;
 
-  if (*arg == nullptr)
+  if (*arg == nullptr || **arg == '\0')
     {
       if (var_type == var_uinteger)
 	error_no_arg (_("integer to set it to, or \"unlimited\"."));
@@ -225,7 +225,7 @@ parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
 {
   LONGEST val;
 
-  if (*arg == nullptr)
+  if (*arg == nullptr || **arg == '\0')
     error_no_arg (_("integer to set it to, or \"unlimited\"."));
 
   if (is_unlimited_literal (arg, expression))
diff --git a/gdb/command.h b/gdb/command.h
index 4d52f00de51..648950b5a44 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -461,14 +461,17 @@ extern void error_no_arg (const char *) ATTRIBUTE_NORETURN;
 
 extern void dont_repeat ();
 
-/* Commands call repeat_previous if they want to repeat the previous command.
-   Such commands that repeat the previous command must indicate
-   to not repeat themselves, to avoid recursive repeat.
-   repeat_previous will mark the current command as not repeating,
-   and will ensure get_saved_command_line returns the previous command,
-   so that the currently executing command can repeat it.  */
-
-extern void repeat_previous ();
+/* Commands call repeat_previous if they want to repeat the previous
+   command.  Such commands that repeat the previous command must
+   indicate to not repeat themselves, to avoid recursive repeat.
+   repeat_previous marks the current command as not repeating, and
+   ensures get_saved_command_line returns the previous command, so
+   that the currently executing command can repeat it.  If there's no
+   previous command, throws an error.  Otherwise, returns the result
+   of get_saved_command_line, which now points at the command to
+   repeat.  */
+
+extern const char *repeat_previous ();
 
 /* Prevent dont_repeat from working, and return a cleanup that
    restores the previous state.  */
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 0509360581e..801651b1e9f 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -44,10 +44,13 @@
 #include "parser-defs.h"
 #include "charset.h"
 #include "arch-utils.h"
+#include "top.h"
 #include "cli/cli-utils.h"
 #include "cli/cli-option.h"
 #include "cli/cli-script.h"
 #include "cli/cli-style.h"
+#include "cli/cli-decode.h"
+#include "cli/cli-setshow.h"
 #include "common/format.h"
 #include "source.h"
 #include "common/byte-vector.h"
@@ -1289,6 +1292,123 @@ set_command (const char *exp, int from_tty)
   evaluate_expression (expr.get ());
 }
 
+/* The "with" command.  */
+
+static void
+with_command (const char *args, int from_tty)
+{
+  const char *delim = strstr (args, "--");
+  const char *nested_cmd = nullptr;
+
+  if (delim == args)
+    error (_("Missing setting before '--' delimiter\n"));
+
+  if (delim == nullptr || *skip_spaces (&delim[2]) == '\0')
+    nested_cmd = repeat_previous ();
+
+  const char *cmd = args;
+  cmd_list_element *set_cmd = lookup_cmd (&args, setlist, "with", 0, 1);
+
+  if (set_cmd == nullptr)
+    error (_("Unknown setting %s"), cmd);
+
+  if (set_cmd->var == nullptr)
+    error (_("Cannot use this setting with the \"with\" command"));
+
+  std::string temp_value
+    = (delim == nullptr ? args : std::string (args, delim - args));
+
+  if (nested_cmd == nullptr)
+    nested_cmd = skip_spaces (delim + 2);
+
+  std::string org_value;
+
+  switch (set_cmd->var_type)
+    {
+    case var_boolean:
+    case var_auto_boolean:
+    case var_integer:
+    case var_zinteger:
+    case var_zuinteger_unlimited:
+      org_value = std::to_string (*(int *) set_cmd->var);
+      break;
+    case var_uinteger:
+    case var_zuinteger:
+      org_value = std::to_string (*(unsigned int *) set_cmd->var);
+      break;
+    case var_string:
+    case var_string_noescape:
+    case var_filename:
+    case var_optional_filename:
+    case var_enum:
+      org_value = *(const char **) set_cmd->var;
+      break;
+    default:
+      gdb_assert_not_reached ("unhandled var_type");
+    }
+
+  /* Tweak the setting to the new temporary value.  */
+  do_set_command (temp_value.c_str (), from_tty, set_cmd);
+
+  try
+    {
+      scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
+
+      /* Execute the nested command.  */
+      execute_command (nested_cmd, from_tty);
+    }
+  catch (const gdb_exception &ex)
+    {
+      /* Restore the setting and rethrow.  If restoring the setting
+	 throws, swallow the new exception and warn.  There's nothing
+	 else we can reasonably do.  */
+      try
+	{
+	  do_set_command (org_value.c_str (), from_tty, set_cmd);
+	}
+      catch (...)
+	{
+	  warning (_("Couldn't restore setting"));
+	}
+
+      throw;
+    }
+
+  /* Restore the setting.  */
+  do_set_command (org_value.c_str (), from_tty, set_cmd);
+}
+
+/* See valprint.h.  */
+
+void
+with_command_completer (struct cmd_list_element *ignore,
+			completion_tracker &tracker,
+			const char *text, const char * /*word*/)
+{
+  tracker.set_use_custom_word_point (true);
+
+  const char *delim = strstr (text, "--");
+
+  /* If we're still not past the "--" delimiter, complete the "with"
+     command as if it was a "set" command.  */
+  if (delim == text
+      || delim == nullptr
+      || !isspace (delim[-1])
+      || !(isspace (delim[2]) || delim[2] == '\0'))
+    {
+      std::string new_text = std::string ("set ") + text;
+      tracker.advance_custom_word_point_by (-(int) strlen ("with"));
+      complete_nested_command_line (tracker, new_text.c_str ());
+      return;
+    }
+
+  /* We're past the "--" delimiter.  Complete on the sub command.  */
+  const char *nested_cmd = skip_spaces (delim + 2);
+  tracker.advance_custom_word_point_by (nested_cmd - text);
+  complete_nested_command_line (tracker, nested_cmd);
+}
+
+
 static void
 info_symbol_command (const char *arg, int from_tty)
 {
@@ -2750,6 +2870,18 @@ Like \"print\" but don't put in value history and don't print newline.\n\
 Usage: output EXP\n\
 This is useful in user-defined commands."));
 
+  c = add_com ("with", class_vars, with_command, _("\
+Temporarily set SETTING to VALUE, run COMMAND, and restore SETTING.\n\
+Usage: with SETTING [VALUE] [-- COMMAND]\n\
+Usage: w SETTING [VALUE] [-- COMMAND]\n\
+SETTING is any setting settable with the \"set\" command.\n\
+E.g.:\n\
+  with language pascal -- print obj\n\
+  with print elements unlimited -- print obj\n\
+\n"));
+  set_cmd_completer_handle_brkchars (c, with_command_completer);
+  add_com_alias ("w", "with", class_vars, 1);
+
   add_prefix_cmd ("set", class_vars, set_command, _("\
 Evaluate expression EXP and assign result to variable VAR\n\
 Usage: set VAR = EXP\n\
diff --git a/gdb/testsuite/gdb.base/with.c b/gdb/testsuite/gdb.base/with.c
new file mode 100644
index 00000000000..c6426625d4a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/with.c
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int xxx1 = 123;
+
+struct S
+{
+  int a;
+  int b;
+  int c;
+};
+
+struct S g_s = {1, 2, 3};
+
+static void
+inc ()
+{
+  g_s.a++;;
+}
+
+int
+main ()
+{
+  inc ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/with.exp b/gdb/testsuite/gdb.base/with.exp
new file mode 100644
index 00000000000..40f0a0f265f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/with.exp
@@ -0,0 +1,168 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the "with" command.
+
+load_lib completion-support.exp
+
+standard_testfile .c
+
+if {[build_executable "failed to prepare" $testfile $srcfile debug]} {
+    return -1
+}
+
+clean_restart $binfile
+
+# Basic/core tests.
+with_test_prefix "basics" {
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}"
+    gdb_test "with print pretty -- print g_s" \
+	[multi_line  \
+	     " = {" \
+	     "  a = 1," \
+	     "  b = 2," \
+	     "  c = 3" \
+	     "}"]
+
+    # A boolean setting.
+    gdb_test "with non-stop on -- show non-stop" \
+	"Controlling the inferior in non-stop mode is on\\."
+    gdb_test "show non-stop" \
+	"Controlling the inferior in non-stop mode is off\\."
+
+    # Language.
+    gdb_test "with language pascal -- show language" \
+	"The current source language is \"pascal\"\\."
+
+    gdb_test "show language" \
+	"The current source language is \"auto; currently c\"\\."
+
+    gdb_test "with language ada -- print g_s" \
+	" = \\(a => 1, b => 2, c => 3\\)"
+
+    # Nested "with"s.
+    gdb_test "with language ada -- with language c -- print g_s" \
+	" = {a = 1, b = 2, c = 3}"
+}
+
+# Check a user defined command.
+with_test_prefix "user defined" {
+    # A user defined command.
+    set test "define usercmd"
+    gdb_test_multiple "define usercmd" $test {
+	-re "End with"  {
+	    gdb_test \
+		[multi_line_input \
+		     {print g_s} \
+		     {end}] \
+		"" \
+		$test
+	}
+    }
+    gdb_test "with language ada -- usercmd" \
+	" = \\(a => 1, b => 2, c => 3\\)"
+}
+
+# Check repeating.
+with_test_prefix "repeat" {
+
+    clean_restart $binfile
+
+    # "with" with no command reinvokes the previous command.
+    gdb_test "with language ada" \
+	"No previous command to relaunch" \
+	"reinvoke with no previous command to relaunch"
+
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}"
+
+    gdb_test "with language ada" \
+	" = \\(a => 1, b => 2, c => 3\\)" \
+	"reinvoke with language"
+
+    # Same, but with "--".
+    gdb_test "with language fortran --" \
+	" = \\( a = 1, b = 2, c = 3 \\)" \
+	"reinvoke with language and --"
+
+    # Repeating repeats the original "print g_s", not the last "with"
+    # command.
+    set test "repeat command line"
+    send_gdb "\n"
+    gdb_test_multiple "" $test {
+	-re " = {a = 1, b = 2, c = 3}\r\n$gdb_prompt $" {
+	    pass $test
+	}
+    }
+}
+
+# Basic run control.
+with_test_prefix "run control" {
+    clean_restart $binfile
+
+    if ![runto_main] {
+	fail "cannot run to main"
+	return
+    }
+
+    # Check "with" with a synchronous execution command.
+    gdb_test "with disassemble-next-line on -- next" \
+	"return 0;.*=>.*"
+}
+
+# Check errors.
+with_test_prefix "errors" {
+    gdb_test "with variable xxx=1" \
+	"Cannot use this setting with the \"with\" command"
+
+    gdb_test "with print elements -- p 1" \
+	"Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
+
+    gdb_test "with -- p 1" \
+	"Missing setting before '--' delimiter"
+
+    # Check that the setting is restored even if the command throws.
+    gdb_test "with print elements 1 -- unknowncommand" \
+	"Undefined command: \"unknowncommand\"\\.  Try \"help\"\\."
+    gdb_test "show print elements" \
+	"Limit on string chars or array elements to print is 200\\."
+}
+
+# Check completion.
+with_test_prefix "completion" {
+    test_gdb_complete_unique \
+	"with pri" \
+	"with print"
+
+    test_gdb_complete_unique \
+	"with print ele" \
+	"with print elements"
+
+    test_gdb_complete_unique \
+	"with print elements u" \
+	"with print elements unlimited"
+
+    test_gdb_complete_none \
+	"with print elements unlimited "
+
+    test_gdb_completion_offers_commands "with print elements unlimited -- "
+
+    # Check that the completer nests into the nested command line's
+    # completer.
+    test_gdb_complete_unique \
+	"with print elements unlimited -- with print ele" \
+	"with print elements unlimited -- with print elements"
+}
diff --git a/gdb/top.c b/gdb/top.c
index b46de90f755..0c02bd1d721 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -739,7 +739,7 @@ dont_repeat (void)
 
 /* See command.h  */
 
-void
+const char *
 repeat_previous ()
 {
   /* Do not repeat this command, as this command is a repeating command.  */
@@ -749,6 +749,11 @@ repeat_previous ()
      so swap it with previous_saved_command_line.  */
   std::swap (previous_saved_command_line, saved_command_line);
   std::swap (previous_repeat_arguments, repeat_arguments);
+
+  const char *prev = skip_spaces (get_saved_command_line ());
+  if (*prev == '\0')
+    error (_("No previous command to relaunch"));
+  return prev;
 }
 
 /* See command.h.  */
