2

I want to run simple bash scripts using laravel command class, but I have not found error. If I go to /var/www/mysite/storage/app/scripts and run script from there in command line, then everything is OK.

$ sh remove-spaces.sh

What is wrong in my Laravel code?

lowercase.sh

for file in /var/www/mysite/storage/app/img/*; 
do mv "$file" "`echo $file | tr '[A-Z]' '[a-z]'`"; 
done

remove-spaces.sh

for file in /var/www/mysite/storage/app/img/*; 
do mv "$file" `echo $file | tr ' ' '-'`; 
done

RenamePicturesCommand

namespace App\Console\Commands\Pictures;
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;

class RenamePicturesCommand extends Command
{
    protected $removeSpaces;
    protected $lowercase;
    protected $signature = 'pictures:rename';

    public function __construct()
    {
        parent::__construct();
        $this->removeSpaces = new Process(['sh /var/www/mysite/storage/app/scripts/remove-spaces.sh']);
        $this->lowercase = new Process(['sh /var/www/mysite/storage/app/scripts/lowercase.sh']);
    }


    public function handle()
    {
        $this->removeSpaces->run();
        if (!$this->removeSpaces->isSuccessful()) {
            throw new ProcessFailedException($this->removeSpaces);
        }
        echo $this->removeSpaces->getOutput();

        $this->lowercase->run();
        if (!$this->lowercase->isSuccessful()) {
            throw new ProcessFailedException($this->lowercase);
        }
        echo $this->lowercase->getOutput();
    }
}

error output

http@0bb690b74597:/var/www/mysite$ php artisan pictures:rename

   Symfony\Component\Process\Exception\ProcessFailedException

  The command "'sh /var/www/mysite/storage/app/scripts/remove-spaces.sh'" failed.

Exit Code: 127(Command not found)

Working directory: /var/www/mysite

Output:
================


Error Output:
================
sh: 1: exec: sh /var/www/mysite/storage/app/scripts/remove-spaces.sh: not found

  at app/Console/Commands/Pictures/RenamePicturesCommand.php:59
     55▕         // execute command
     56▕         $this->removeSpaces->run();
     57▕         // executes after the command finishes
     58▕         if (!$this->removeSpaces->isSuccessful()) {
  ➜  59▕             throw new ProcessFailedException($this->removeSpaces);
     60▕         }
     61▕         echo $this->removeSpaces->getOutput();
     62▕
     63▕

      +13 vendor frames
  14  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

2
  • Not related to the issue - but why do you want to use shell script for renaming files. It can be done with the Storage facade easily without having the need to run shell script. Commented Jun 16, 2022 at 21:50
  • First, use the Storage manager that comes with laravel. exec("sh your_script.sh", $output); $this->comment( implode( PHP_EOL, $output ) ); Commented Jun 16, 2022 at 22:45

1 Answer 1

2

You may try to provide the command and argument as two separate items in the commands array

namespace App\Console\Commands\Pictures;
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;

class RenamePicturesCommand extends Command
{
    protected $removeSpaces;
    protected $lowercase;
    protected $signature = 'pictures:rename';

    public function __construct()
    {
        parent::__construct();
        $this->removeSpaces = new Process(['sh', '/var/www/mysite/storage/app/scripts/remove-spaces.sh']);
        $this->lowercase = new Process(['sh', '/var/www/mysite/storage/app/scripts/lowercase.sh']);

        //Or you can use Process::fromShellCommandline
        //$this->removeSpaces =Process::fromShellCommandline('sh /Volumes/samsung-250/Sites/stackoverflow/storage/app/scripts/lowercase.sh');
        //$this->lowercase =Process::fromShellCommandline('sh /Volumes/samsung-250/Sites/stackoverflow/storage/app/scripts/remove-spaces.sh');
    }


    public function handle()
    {
        $this->removeSpaces->run();
        if (!$this->removeSpaces->isSuccessful()) {
            throw new ProcessFailedException($this->removeSpaces);
        }
        echo $this->removeSpaces->getOutput();

        $this->lowercase->run();
        if (!$this->lowercase->isSuccessful()) {
            throw new ProcessFailedException($this->lowercase);
        }
        echo $this->lowercase->getOutput();
    }
}

You can also achieve the same results with Storage facade without any shell script

namespace App\Console\Commands\Pictures;

use Illuminate\Console\Command;
use Illuminate\Support\LazyCollection;

class RenamePicturesCommand extends Command
{
    protected $signature = 'pictures:rename';


    public function handle()
    {
        $this->info('Renaming pictures...');
        $this->newLine(2);

        $files = LazyCollection::make(Storage::disk('local')->files('img'))
            //Remove dotfiles
            ->reject(fn($filePath) => Str::startsWith($filePath, '.'));

        $progress = $this->output->createProgressBar($files->count());
        $progress->start();

        $modified = [];

        $files->each(function ($file) use ($progress, &$modified) {

            $new = strtolower(preg_replace('/\s+/', '-', $file));

            $temp = ['old' => $file, 'new' => $new, 'status' => 'success'];

            if(! Storage::disk('local')->move($file, $new)) {
                $temp['status'] = 'failed';
                $temp['new'] = $file;
            }

            $modified[] = $temp;

            $progress->advance();
        });

        
        $this->newLine(2);
        $this->info('Finished Renaming pictures');
        $this->newLine(2);
        $this->table(['Old', 'New', 'Status'], $modified);
    }
}
Sign up to request clarification or add additional context in comments.

10 Comments

Your second solution is interesting, but it doesn't work. It gives me error File already exists at path: img/glass/_work/2013--10-01-16.58.20.jpg But in reality there is no dublicate file app/Console/Commands/Pictures/RenamePicturesCommand.php:71 Illuminate\Filesystem\FilesystemAdapter::move("img/glass/_work/2013- 10-01-16.58.20.jpg", "img/glass/_work/2013--10-01-16.58.20.jpg") Here is the screenshot disk.yandex.ru/d/-d_nX6E2FuRaxg
@schel4ok Does the script solution work properly? Under the hood Storage::move uses php rename which will overwrite a file if it exists, except for on windows os where it will throw an error.
what do you mean "Does the script solution work properly?"
@schel4ok The solution involving shell script as per the original question. Using either Process::fromShellCommandline or new Process & separating the command sh and arguments as two elements of the array passed to new Process
1) My initial solution with new Process always gives me Symfony\Component\Process\Exception\ProcessFailedException ➜ 69▕ throw new ProcessFailedException($this->removeSpaces); The command "'sh /var/www/mysite/storage/app/scripts/remove-spaces.sh'" failed. Exit Code: 127(Command not found) And no even one file renamed.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.