Repository: peak/s5cmd (go)

Issue:
Unable to process files with a hash sign in commands file
When using the `run` command, it's not possible to process files which have a `#` in their names (which is a valid character in S3), as they are interpreted as inline comments. 

It's not possible to escape them either, as the `\` is passed on to S3. 

Example with file `s3://dummy/foo/test \#3 /bar.jpg`  (filenames were removed) : 
```
$ s5cmd --dry-run run test                                                          
mv s3://dummy/foo/test \#3 /bar.jpg s3://dummy/foo/test \#3/bar.jpg
$ s5cmd --log debug run test
ERROR "mv s3://dummy/foo/test \\#3 /bar.jpg s3://dummy/foo/test \\#3/bar.jpg": NoSuchKey: The specified key does not exist. status code: 404, request id: DJQNRYQN42QTWC7E, host id: YF1dXLn/wFe7VXNidbR8KCgZVRWqYdtpLmnvDDM9WfIGVSq3egUslUjQ8lgOlRnAON1B0Rkgr3Y=
```

Pull request:
command/run: drop inline comment support
Previously s5cmd supported a command with an inline comment like `ls s3://bucket/object.gz  # inline comment`.

Comment per line is still supported.

Fixes #309


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f180dc..266ffbb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,9 +2,12 @@
 
 ## not released yet
 
+#### Breaking changes
+- Dropped inline comment feature for `run` command. Previously s5cmd supported a command with an inline comment like `ls s3://bucket/object.gz  # inline comment`. ([#309](https://github.com/peak/s5cmd/issues/309))
+
 #### Features
 - Added `--ignore-glacier-warnings` flag to `cp`, `mv` and `select` commands. ([#346](https://github.com/peak/s5cmd/issues/346))
-- Added `--force-glacier-transfer` flag to `select` command. ([#404](https://github.com/peak/s5cmd/pull/404))
+- Added `--force-glacier-transfer` flag to `select` command. ([#346](https://github.com/peak/s5cmd/issues/346))
 - Added AWS Single Sign-On (SSO) profiles support ([#385](https://github.com/peak/s5cmd/issues/385))
 - Added `--use-v1-api` flag to force using S3 ListObjects API instead of ListObjectsV2 API. ([#405](https://github.com/peak/s5cmd/issues/405)
 
diff --git a/command/run.go b/command/run.go
index d7596a9..37e8cb9 100644
--- a/command/run.go
+++ b/command/run.go
@@ -102,14 +102,12 @@ func (r Run) Run(ctx context.Context) error {
 	for line := range scanner.Scan() {
 		lineno++
 
-		// support inline comments
-		line = strings.Split(line, " #")[0]
-
 		line = strings.TrimSpace(line)
 		if line == "" {
 			continue
 		}
 
+		// skip comment lines
 		if strings.HasPrefix(line, "#") {
 			continue
 		}


Test patch:
diff --git a/e2e/run_test.go b/e2e/run_test.go
index 94d3f2b..b695222 100644
--- a/e2e/run_test.go
+++ b/e2e/run_test.go
@@ -25,9 +25,10 @@ func TestRunFromStdin(t *testing.T) {
 
 	input := strings.NewReader(
 		strings.Join([]string{
-			fmt.Sprintf("ls s3://%v/file1.txt", bucket),
 			" # this is a comment",
-			fmt.Sprintf("ls s3://%v/file2.txt # this is an inline comment", bucket),
+			fmt.Sprintf("ls s3://%v/file1.txt", bucket),
+			"# this one too",
+			fmt.Sprintf("ls s3://%v/file2.txt", bucket),
 		}, "\n"),
 	)
 	cmd := s5cmd("run")
@@ -43,6 +44,35 @@ func TestRunFromStdin(t *testing.T) {
 	assertLines(t, result.Stderr(), map[int]compareFunc{})
 }
 
+func TestRunFromStdinIssue309(t *testing.T) {
+	t.Parallel()
+
+	bucket := s3BucketFromTestName(t)
+
+	s3client, s5cmd, cleanup := setup(t)
+	defer cleanup()
+
+	createBucket(t, s3client, bucket)
+	putFile(t, s3client, bucket, "test #3 /bar.jpg", "content")
+
+	input := strings.NewReader(
+		strings.Join([]string{
+			" # this is a comment",
+			fmt.Sprintf("mv 's3://%v/test #3 /bar.jpg' 's3://%v/test #3/bar.jpg'", bucket, bucket),
+		}, "\n"),
+	)
+	cmd := s5cmd("run")
+	result := icmd.RunCmd(cmd, icmd.WithStdin(input))
+
+	result.Assert(t, icmd.Success)
+
+	assertLines(t, result.Stdout(), map[int]compareFunc{
+		0: suffix("mv s3://test-run-from-stdin-issue-309/test #3 /bar.jpg s3://test-run-from-stdin-issue-309/test #3/bar.jpg"),
+	})
+
+	assertLines(t, result.Stderr(), map[int]compareFunc{})
+}
+
 func TestRunFromStdinWithErrors(t *testing.T) {
 	t.Parallel()