diff --git a/gdb/main.c b/gdb/main.c
index 12f0146..756dd4f 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -45,6 +45,7 @@
 #include "filestuff.h"
 #include <signal.h>
 #include "event-top.h"
+#include "infrun.h"
 
 /* The selected interpreter.  This will be used as a set command
    variable, so it should always be malloc'ed - since
@@ -369,7 +370,11 @@ catch_command_errors (catch_command_errors_ftype *command,
 
   TRY_CATCH (e, mask)
     {
+      int was_sync = sync_execution;
+
       command (arg, from_tty);
+
+      maybe_wait_sync_command_done (was_sync);
     }
   return handle_command_errors (e);
 }
@@ -388,7 +393,11 @@ catch_command_errors_const (catch_command_errors_const_ftype *command,
 
   TRY_CATCH (e, mask)
     {
+      int was_sync = sync_execution;
+
       command (arg, from_tty);
+
+      maybe_wait_sync_command_done (was_sync);
     }
   return handle_command_errors (e);
 }
diff --git a/gdb/testsuite/gdb.base/attach.exp b/gdb/testsuite/gdb.base/attach.exp
index a20c51a..6340496 100644
--- a/gdb/testsuite/gdb.base/attach.exp
+++ b/gdb/testsuite/gdb.base/attach.exp
@@ -396,6 +396,49 @@ proc do_command_attach_tests {} {
     remote_exec build "kill -9 ${testpid}"
 }
 
+# Test ' gdb --pid PID -ex "run" '.  GDB used to have a bug where
+# "run" would run before the attach finished - PR17347.
+
+proc test_command_line_attach_run {} {
+    global gdb_prompt
+    global binfile
+
+    if ![isnative] then {
+	unsupported "commandline attach run test"
+	return 0
+    }
+
+    with_test_prefix "cmdline attach run" {
+	set testpid [spawn_wait_for_attach $binfile]
+
+	set test "run to prompt"
+	gdb_exit
+
+	set res [gdb_spawn_with_cmdline_opts \
+		     "-iex \"set height 0\" -iex \"set width 0\" --pid=$testpid -ex \"start\""]
+	if { $res != 0} {
+	    fail $test
+	    return $res
+	}
+	gdb_test_multiple "" $test {
+	    -re {Attaching to.*Start it from the beginning\? \(y or n\) } {
+		pass $test
+	    }
+	}
+
+	send_gdb "y\n"
+
+	set test "run to main"
+	gdb_test_multiple "" $test {
+	    -re "Temporary breakpoint .* main .*$gdb_prompt $" {
+		pass $test
+	    }
+	}
+
+	# Get rid of the process
+	remote_exec build "kill -9 ${testpid}"
+    }
+}
 
 # Start with a fresh gdb
 
@@ -420,4 +463,6 @@ do_call_attach_tests
 
 do_command_attach_tests
 
+test_command_line_attach_run
+
 return 0
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index ecf942e..c54ba4b 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -3334,6 +3334,22 @@ proc gdb_spawn { } {
     default_gdb_spawn
 }
 
+# Spawn GDB with CMDLINE_FLAGS appended to the GDBFLAGS global.
+
+proc gdb_spawn_with_cmdline_opts { cmdline_flags } {
+    global GDBFLAGS
+
+    set saved_gdbflags $GDBFLAGS
+
+    append GDBFLAGS $cmdline_flags
+
+    set res [gdb_spawn]
+
+    set GDBFLAGS $saved_gdbflags
+
+    return $res
+}
+
 # Start gdb running, wait for prompt, and disable the pagers.
 
 # Overridable function -- you can override this function in your
diff --git a/gdb/top.c b/gdb/top.c
index fc2b84d..d6696cd 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -373,6 +373,23 @@ check_frame_language_change (void)
     }
 }
 
+/* See top.h.  */
+
+void
+maybe_wait_sync_command_done (int was_sync)
+{
+  /* If the interpreter is in sync mode (we're running a user
+     command's list, running command hooks or similars), and we
+     just ran a synchronous command that started the target, wait
+     for that command to end.  */
+  if (!interpreter_async && !was_sync && sync_execution)
+    {
+      while (gdb_do_one_event () >= 0)
+	if (!sync_execution)
+	  break;
+    }
+}
+
 /* Execute the line P as a command, in the current user context.
    Pass FROM_TTY as second argument to the defining function.  */
 
@@ -459,16 +476,7 @@ execute_command (char *p, int from_tty)
       else
 	cmd_func (c, arg, from_tty);
 
-      /* If the interpreter is in sync mode (we're running a user
-	 command's list, running command hooks or similars), and we
-	 just ran a synchronous command that started the target, wait
-	 for that command to end.  */
-      if (!interpreter_async && !was_sync && sync_execution)
-	{
-	  while (gdb_do_one_event () >= 0)
-	    if (!sync_execution)
-	      break;
-	}
+      maybe_wait_sync_command_done (was_sync);
 
       /* If this command has been post-hooked, run the hook last.  */
       execute_cmd_post_hook (c);
diff --git a/gdb/top.h b/gdb/top.h
index c322c33..94f6c48 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -42,6 +42,14 @@ extern void quit_command (char *, int);
 extern void quit_cover (void);
 extern void execute_command (char *, int);
 
+/* If the interpreter is in sync mode (we're running a user command's
+   list, running command hooks or similars), and we just ran a
+   synchronous command that started the target, wait for that command
+   to end.  WAS_SYNC indicates whether sync_execution was set before
+   the command was run.  */
+
+extern void maybe_wait_sync_command_done (int was_sync);
+
 extern void check_frame_language_change (void);
 
 /* Prepare for execution of a command.
