dcli
  • Introduction
  • What does DCli do?
  • Install DCli
    • Installing on Windows
  • Writing your first CLI app
  • Add DCli to your project
  • pub.dev
  • github
  • Dart basics
    • Dart lambda functions
    • Function Arguments
    • Futures
    • stdin/stdout/stderr a primer
  • Tour
    • Overview
    • Using DCli functions
    • User input
      • Ask Validators
    • Displaying information
    • Managing Files And Directories
    • Environment variables
    • Calling apps
    • Redirecting output
    • Command Line Arguments
    • Paths
    • Glob Expansion
    • Piping
    • Locking
    • Fetch
    • The evils of CD
    • Assets/Resources
    • Cross Platform
      • Posix
      • Windows
      • Docker
        • Detecting Docker
        • Add DCli to a Docker Container
        • Example DCli app in Docker
  • Elevated Privileges
    • Sudo
  • Performance
  • Dependency Management
    • Dependency Management
    • Pubspec Managment
  • DCli Tools
    • DCli tools
    • Use a shebang #!
    • DCli Compile
    • DCli Clean
    • DCli Create
    • DCli Doctor
    • DCli Install
    • DCli Run
    • DCli Warmup
    • DCli Pack
    • Upgrade DCli
  • Internal Workings
    • Internal Workings
    • waitForEx
  • Contributing
    • Creating a release
    • Running Unit tests
    • Implemention support for a shell
    • Templates
  • References
  • Examples
    • Projects
    • Code
      • hello world.
      • dcompress
      • dpath
      • dmysql
      • dshell
      • dwhich
      • dipaddr
      • gnome launcher
  • Articles
    • build CLI apps in dart - part 1
    • build CLI apps in dart - part 2
    • Dealing with permissions
    • 3rd Party console packages
  • Dart on Linux - the perfect CLI tooling
  • Improving your build environment
    • Existing tooling
    • Building with Dart
    • A home for your build tools
  • Olivier Revial - CLI apps made easy
  • Video: package of the week
Powered by GitBook
On this page
  • CD/pushd/popd are evil
  • Why is cd dangerous?

Was this helpful?

  1. Tour

The evils of CD

PreviousFetchNextAssets/Resources

Last updated 2 years ago

Was this helpful?

CD/pushd/popd are evil

For complete API documentation refer to:

The cd, pushd and popd commands of Bash seem like fun but they are actually harbingers of evil.

I know that they are used everywhere and they seem such an elegant solution but in a script they just shouldn't be used.

So if you shouldn't use cd, pushd or popd what should you do instead?

There a three basic techniques you will use:

  • absolute paths

  • use the 'start()' method with a working directory

  • relative paths

DCli automatically injects the rather excellent package which includes an array of global functions that allow you to build and manipulate file paths to create relative and absolute paths.

You should prefer absolute paths over relative paths.

Such as:

String filePath = join(HOME, 'directory', 'file.txt');

String dartPath = join('/', 'usr', 'lib', 'bin', 'dart');

// absolute path to your current working directory.
String current = absolute('.');

// create a safe path by replacing the segments (..) with the real path.
String safe = canonicalize(join('..', '..', 'hacker'));

String dirname = dirname(join('usr', 'lib', 'fred.text'));
assert(dirname == '/usr/lib');

Often when running an application you need to set the working directory to run the command in.

The following examples runs the command 'git status' from the working directory

/home/yourhome/dev/myproject.

// run a command using a specific working directory
'git status'.start(workingDirectory: join(HOME, 'dev', 'myproject'));

`

With the path package at your disposal there is really no need to use cd, pushd or popd.

Why is cd dangerous?

There are several reasons.

1) Dart is multi-threaded

This probably won't be an issue for you as DCli will NEVER start an Isolate and most scripts don't need to use Isolates, but best pratices says that you should assume that one day you might just need to use one, so read on...

Dart and consequently DCli allow you to run multiple threads of execution via Isolates.

The problem is that all of these Isolates running in your Dart process share a single common working directory (CWD or PWD).

This means that if you use CD in one isolate, then all other isolates have their working directory changed under their feet.

Imagine if you are about to do a recusive delete in one isolate and some other Isolate changes the working directory to /.

Oops you just deleted your entire file system.

2) A function forgets to pop

What happens if you call a function that happens to change the working directory?

Again you can end up deleting your entire file system if the function changes to /.

3) Another process deletes your working directory What happens if another process deletes your working directory just as you are about to delete all of its contents? If you are using the 'paths' package then it will climb the path until it finds a directory that exists and set that as you new working directory. Your new working directory could well be the root directory.

The correct answer is simply don't use CD/PUSH/POP.

Use relative or preferably absolute paths.

pub.dev
'path'