function ShellString(stdout, stderr, code) { var that; if (stdout instanceof Array) { that = stdout; that.stdout = stdout.join('\n'); if (stdout.length > 0) that.stdout += '\n'; } else { that = new String(stdout); that.stdout = stdout; } that.stderr = stderr; that.code = code; // A list of all commands that can appear on the right-hand side of a pipe // (populated by calls to common.wrap()) pipeMethods.forEach(function (cmd) { that[cmd] = shellMethods[cmd].bind(that); }); return that; }
...
// Dest is not existing dir, but multiple sources given
if ((!destExists || !destStat.isDirectory()) && sources.length > 1) {
common.error('dest is not a directory (too many sources)');
}
// Dest is an existing file, but -n is given
if (destExists && destStat.isFile() && options.no_force) {
return new common.ShellString('', '', 0);
}
sources.forEach(function (src) {
if (!fs.existsSync(src)) {
common.error('no such file or directory: ' + src, { continue: true });
return; // skip file
}
...
cat = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js
x27;), file);
});
shell.cd('..');
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
shell.echo('Error: Git commit failed');
shell.exit(1);
...
cd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
...
chmod = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
cp = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
...
dirs = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
echo = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
## Examples
```javascript
var shell = require('shelljs');
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
...
function error() { return common.state.error; }
...
//@
//@ Returns a string containing the given file, or a concatenated string
//@ containing the files if more than one file is given (a new line character is
//@ introduced between each file).
function _cat(options, files) {
var cat = common.readFromPipe();
if (!files && !cat) common.error('no paths given');
files = [].slice.call(arguments, 1);
files.forEach(function (file) {
if (!fs.existsSync(file)) {
common.error('no such file or directory: ' + file);
}
...
exec = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
shell.echo('Error: Git commit failed');
shell.exit(1);
}
```
## Global vs. Local
...
exit = function () {
/*
* this function will do nothing
*/
return;
}
...
## Examples
```javascript
var shell = require('shelljs');
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
...
find = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
grep = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
### Pipes
Examples:
```javascript
grep('foo', 'file1.txt', 'file2.txt').sed(/o/g, 'a').to('output.txt');
echo('files with o\'s in the name:\n' + ls().grep('o'));
cat('test.js').exec('node'); // pipe to exec() call
```
Commands can send their output to another command in a pipe-like fashion.
`sed`, `grep`, `cat`, `exec`, `to`, and `toEnd` can appear on the right-hand
side of a pipe. Pipes can be chained.
...
head = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
ln = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
ls = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
// Run external tool synchronously
...
mkdir = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
mv = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
popd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
pushd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
pwd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
rm = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
...
sed = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
...
set = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
sort = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
}
var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8');
lines = lines.concat(contents.trimRight().split(/\r*\n/));
});
var sorted;
sorted = lines.sort(options.numerical ? numericalCmp : unixCmp);
if (options.reverse) {
sorted = sorted.reverse();
}
return sorted.join('\n') + '\n';
}
...
tail = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
tempdir = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
test = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
// $ cd ../../../..
// $ cp -RL 1 copy
var cyclecheck = fs.statSync(srcFile);
if (cyclecheck.isDirectory()) {
var sourcerealpath = fs.realpathSync(sourceDir);
var symlinkrealpath = fs.realpathSync(srcFile);
var re = new RegExp(symlinkrealpath);
if (re.test(sourcerealpath)) {
return true;
}
}
}
return false;
}
...
touch = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
uniq = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
which = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
```
## Examples
```javascript
var shell = require('shelljs');
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
...
function ShellString(stdout, stderr, code) { var that; if (stdout instanceof Array) { that = stdout; that.stdout = stdout.join('\n'); if (stdout.length > 0) that.stdout += '\n'; } else { that = new String(stdout); that.stdout = stdout; } that.stderr = stderr; that.code = code; // A list of all commands that can appear on the right-hand side of a pipe // (populated by calls to common.wrap()) pipeMethods.forEach(function (cmd) { that[cmd] = shellMethods[cmd].bind(that); }); return that; }
...
// Dest is not existing dir, but multiple sources given
if ((!destExists || !destStat.isDirectory()) && sources.length > 1) {
common.error('dest is not a directory (too many sources)');
}
// Dest is an existing file, but -n is given
if (destExists && destStat.isFile() && options.no_force) {
return new common.ShellString('', '', 0);
}
sources.forEach(function (src) {
if (!fs.existsSync(src)) {
common.error('no such file or directory: ' + src, { continue: true });
return; // skip file
}
...
function convertErrorOutput(msg) { if (typeof msg !== 'string') { throw new TypeError('input must be a string'); } return msg.replace(/\\/g, '/'); }
n/a
function error(msg, _code, options) { // Validate input if (typeof msg !== 'string') throw new Error('msg must be a string'); var DEFAULT_OPTIONS = { continue: false, code: 1, prefix: state.currentCmd + ': ', silent: false, }; if (typeof _code === 'number' && isObject(options)) { options.code = _code; } else if (isObject(_code)) { // no 'code' options = _code; } else if (typeof _code === 'number') { // no 'options' options = { code: _code }; } else if (typeof _code !== 'number') { // only 'msg' options = {}; } options = objectAssign({}, DEFAULT_OPTIONS, options); if (!state.errorCode) state.errorCode = options.code; var logEntry = convertErrorOutput(options.prefix + msg); state.error = state.error ? state.error + '\n' : ''; state.error += logEntry; // Throw an error, or log the entry if (config.fatal) throw new Error(logEntry); if (msg.length > 0 && !options.silent) log(logEntry); if (!options.continue) { throw { msg: 'earlyExit', retValue: (new ShellString('', state.error, state.errorCode)), }; } }
...
//@
//@ Returns a string containing the given file, or a concatenated string
//@ containing the files if more than one file is given (a new line character is
//@ introduced between each file).
function _cat(options, files) {
var cat = common.readFromPipe();
if (!files && !cat) common.error('no paths given');
files = [].slice.call(arguments, 1);
files.forEach(function (file) {
if (!fs.existsSync(file)) {
common.error('no such file or directory: ' + file);
}
...
function expand(list) { if (!Array.isArray(list)) { throw new TypeError('must be an array'); } var expanded = []; list.forEach(function (listEl) { // Don't expand non-strings if (typeof listEl !== 'string') { expanded.push(listEl); } else { var ret = glob.sync(listEl, config.globOptions); // if glob fails, interpret the string literally expanded = expanded.concat(ret.length > 0 ? ret : [listEl]); } }); return expanded; }
...
'v': 'verbose',
});
filePattern = [].slice.call(arguments, 2);
var files;
// TODO: replace this with a call to common.expand()
if (options.recursive) {
files = [];
filePattern.forEach(function addFile(expandedFile) {
var stat = fs.lstatSync(expandedFile);
if (!stat.isSymbolicLink()) {
files.push(expandedFile);
...
function assign() { [native code] }
...
var tempDir = _tempDir();
var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName());
var stderrFile = path.resolve(tempDir + '/' + common.randomFileName());
var codeFile = path.resolve(tempDir + '/' + common.randomFileName());
var scriptFile = path.resolve(tempDir + '/' + common.randomFileName());
var sleepFile = path.resolve(tempDir + '/' + common.randomFileName());
opts = common.extend({
silent: common.config.silent,
cwd: _pwd().toString(),
env: process.env,
maxBuffer: DEFAULT_MAXBUFFER_SIZE,
}, opts);
var previousStdoutContent = '';
...
function getUserHome() { var result; if (os.homedir) { result = os.homedir(); // node 3+ } else { result = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; } return result; }
...
common.register('cd', _cd, {});
//@
//@ ### cd([dir])
//@ Changes to directory `dir` for the duration of the script. Changes to home
//@ directory if no argument is supplied.
function _cd(options, dir) {
if (!dir) dir = common.getUserHome();
if (dir === '-') {
if (!process.env.OLDPWD) {
common.error('could not find previous directory');
} else {
dir = process.env.OLDPWD;
}
...
function isObject(a) { return typeof a === 'object' && a !== null; }
n/a
function log() {
/* istanbul ignore next */
if (!config.silent) {
console.error.apply(console, arguments);
}
}
...
var child = exec('some_long_running_process', {async:true});
child.stdout.on('data', function(data) {
/* ... do something with data ... */
});
exec('some_long_running_process', function(code, stdout, stderr) {
console.log('Exit code:', code);
console.log('Program output:', stdout);
console.log('Program stderr:', stderr);
});
```
Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous
mode, this returns a ShellString (compatible with ShellJS v0.6.x, which returns an object
...
function parseOptions(opt, map, errorOptions) { // Validate input if (typeof opt !== 'string' && !isObject(opt)) { throw new Error('options must be strings or key-value pairs'); } else if (!isObject(map)) { throw new Error('parseOptions() internal error: map must be an object'); } else if (errorOptions && !isObject(errorOptions)) { throw new Error('parseOptions() internal error: errorOptions must be object'); } // All options are false by default var options = {}; Object.keys(map).forEach(function (letter) { var optName = map[letter]; if (optName[0] !== '!') { options[optName] = false; } }); if (opt === '') return options; // defaults if (typeof opt === 'string') { if (opt[0] !== '-') { error("Options string must start with a '-'", errorOptions || {}); } // e.g. chars = ['R', 'f'] var chars = opt.slice(1).split(''); chars.forEach(function (c) { if (c in map) { var optionName = map[c]; if (optionName[0] === '!') { options[optionName.slice(1)] = false; } else { options[optionName] = true; } } else { error('option not recognized: ' + c, errorOptions || {}); } }); } else { // opt is an Object Object.keys(opt).forEach(function (key) { // key is a string of the form '-r', '-d', etc. var c = key[1]; if (c in map) { var optionName = map[c]; options[optionName] = opt[key]; // assign the given value } else { error('option not recognized: ' + c, errorOptions || {}); } }); } return options; }
...
// If we are down by one argument and options starts with -, shift everything over.
[].unshift.call(arguments, '');
} else {
common.error('You must specify a file.');
}
}
options = common.parseOptions(options, {
'R': 'recursive',
'c': 'changes',
'v': 'verbose',
});
filePattern = [].slice.call(arguments, 2);
...
function randomFileName() { function randomHash(count) { if (count === 1) { return parseInt(16 * Math.random(), 10).toString(16); } var hash = ''; for (var i = 0; i < count; i++) { hash += randomHash(1); } return hash; } return 'shelljs_' + randomHash(20); }
...
// event loop).
function execSync(cmd, opts, pipe) {
if (!common.config.execPath) {
common.error('Unable to find a path to the node binary. Please manually set config.execPath');
}
var tempDir = _tempDir();
var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName());
var stderrFile = path.resolve(tempDir + '/' + common.randomFileName());
var codeFile = path.resolve(tempDir + '/' + common.randomFileName());
var scriptFile = path.resolve(tempDir + '/' + common.randomFileName());
var sleepFile = path.resolve(tempDir + '/' + common.randomFileName());
opts = common.extend({
silent: common.config.silent,
...
function _readFromPipe() { return state.pipedValue; }
...
//@ var str = cat(['file1', 'file2']); // same as above
//@ ```
//@
//@ Returns a string containing the given file, or a concatenated string
//@ containing the files if more than one file is given (a new line character is
//@ introduced between each file).
function _cat(options, files) {
var cat = common.readFromPipe();
if (!files && !cat) common.error('no paths given');
files = [].slice.call(arguments, 1);
files.forEach(function (file) {
if (!fs.existsSync(file)) {
...
function _register(name, implementation, wrapOptions) { wrapOptions = wrapOptions || {}; // If an option isn't specified, use the default wrapOptions = objectAssign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); if (shell[name] && !wrapOptions.overWrite) { throw new Error('unable to overwrite `' + name + '` command'); } if (wrapOptions.pipeOnly) { wrapOptions.canReceivePipe = true; shellMethods[name] = wrap(name, implementation, wrapOptions); } else { shell[name] = wrap(name, implementation, wrapOptions); } }
...
var common = require('./common');
var fs = require('fs');
common.register('cat', _cat, {
canReceivePipe: true,
});
//@
//@ ### cat(file [, file ...])
//@ ### cat(file_array)
//@
...
function unlinkSync(file) {
try {
fs.unlinkSync(file);
} catch (e) {
// Try to override file permission
/* istanbul ignore next */
if (e.code === 'EPERM') {
fs.chmodSync(file, '0666');
fs.unlinkSync(file);
} else {
throw e;
}
}
}
...
}
exports.expand = expand;
// Normalizes _unlinkSync() across platforms to match Unix behavior, i.e.
// file can be unlinked even if it's read-only, see https://github.com/joyent/node/issues/3006
function unlinkSync(file) {
try {
fs.unlinkSync(file);
} catch (e) {
// Try to override file permission
/* istanbul ignore next */
if (e.code === 'EPERM') {
fs.chmodSync(file, '0666');
fs.unlinkSync(file);
} else {
...
function wrap(cmd, fn, options) {
options = options || {};
if (options.canReceivePipe) {
pipeMethods.push(cmd);
}
return function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
};
}
...
var shell = require('./shell.js');
var common = require('./src/common');
Object.keys(shell).forEach(function (cmd) {
global[cmd] = shell[cmd];
});
var _to = require('./src/to');
String.prototype.to = common.wrap('to', _to);
var _toEnd = require('./src/toEnd');
String.prototype.toEnd = common.wrap('toEnd', _toEnd);
...
reset = function () { objectAssign(this, DEFAULT_CONFIG); if (!isElectron) { this.execPath = process.execPath; } }
...
```javascript
config.globOptions = {nodir: true};
```
Use this value for calls to `glob.sync()` instead of the default options.
### config.reset()
Example:
```javascript
var shell = require('shelljs');
// Make changes to shell.config, and do stuff...
/* ... */
...
resetForTesting = function () { this.reset(); this.silent = true; }
n/a
function _dirs(options, index) { if (_isStackIndex(options)) { index = options; options = ''; } options = common.parseOptions(options, { 'c': 'clear', }); if (options.clear) { _dirStack = []; return _dirStack; } var stack = _actualDirStack(); if (index) { index = _parseStackIndex(index); if (index < 0) { index = stack.length + index; } common.log(stack[index]); return stack[index]; } common.log(stack.join(' ')); return stack; }
n/a
function _popd(options, index) { if (_isStackIndex(options)) { index = options; options = ''; } options = common.parseOptions(options, { 'n': 'no-cd', }); if (!_dirStack.length) { return common.error('directory stack empty'); } index = _parseStackIndex(index || '+0'); if (options['no-cd'] || index > 0 || _dirStack.length + index === 0) { index = index > 0 ? index - 1 : index; _dirStack.splice(index, 1); } else { var dir = path.resolve(_dirStack.shift()); _cd('', dir); } return _dirs(''); }
n/a
function _pushd(options, dir) { if (_isStackIndex(options)) { dir = options; options = ''; } options = common.parseOptions(options, { 'n': 'no-cd', }); var dirs = _actualDirStack(); if (dir === '+0') { return dirs; // +0 is a noop } else if (!dir) { if (dirs.length > 1) { dirs = dirs.splice(1, 1).concat(dirs); } else { return common.error('no other directory'); } } else if (_isStackIndex(dir)) { var n = _parseStackIndex(dir); dirs = dirs.slice(n).concat(dirs.slice(0, n)); } else { if (options['no-cd']) { dirs.splice(1, 0, dir); } else { dirs.unshift(dir); } } if (options['no-cd']) { dirs = dirs.slice(1); } else { dir = path.resolve(dirs.shift()); _cd('', dir); } _dirStack = dirs; return _dirs(''); }
n/a
function error(msg, _code, options) { // Validate input if (typeof msg !== 'string') throw new Error('msg must be a string'); var DEFAULT_OPTIONS = { continue: false, code: 1, prefix: state.currentCmd + ': ', silent: false, }; if (typeof _code === 'number' && isObject(options)) { options.code = _code; } else if (isObject(_code)) { // no 'code' options = _code; } else if (typeof _code === 'number') { // no 'options' options = { code: _code }; } else if (typeof _code !== 'number') { // only 'msg' options = {}; } options = objectAssign({}, DEFAULT_OPTIONS, options); if (!state.errorCode) state.errorCode = options.code; var logEntry = convertErrorOutput(options.prefix + msg); state.error = state.error ? state.error + '\n' : ''; state.error += logEntry; // Throw an error, or log the entry if (config.fatal) throw new Error(logEntry); if (msg.length > 0 && !options.silent) log(logEntry); if (!options.continue) { throw { msg: 'earlyExit', retValue: (new ShellString('', state.error, state.errorCode)), }; } }
...
//@
//@ Returns a string containing the given file, or a concatenated string
//@ containing the files if more than one file is given (a new line character is
//@ introduced between each file).
function _cat(options, files) {
var cat = common.readFromPipe();
if (!files && !cat) common.error('no paths given');
files = [].slice.call(arguments, 1);
files.forEach(function (file) {
if (!fs.existsSync(file)) {
common.error('no such file or directory: ' + file);
}
...
function parseOptions(opt, map, errorOptions) { // Validate input if (typeof opt !== 'string' && !isObject(opt)) { throw new Error('options must be strings or key-value pairs'); } else if (!isObject(map)) { throw new Error('parseOptions() internal error: map must be an object'); } else if (errorOptions && !isObject(errorOptions)) { throw new Error('parseOptions() internal error: errorOptions must be object'); } // All options are false by default var options = {}; Object.keys(map).forEach(function (letter) { var optName = map[letter]; if (optName[0] !== '!') { options[optName] = false; } }); if (opt === '') return options; // defaults if (typeof opt === 'string') { if (opt[0] !== '-') { error("Options string must start with a '-'", errorOptions || {}); } // e.g. chars = ['R', 'f'] var chars = opt.slice(1).split(''); chars.forEach(function (c) { if (c in map) { var optionName = map[c]; if (optionName[0] === '!') { options[optionName.slice(1)] = false; } else { options[optionName] = true; } } else { error('option not recognized: ' + c, errorOptions || {}); } }); } else { // opt is an Object Object.keys(opt).forEach(function (key) { // key is a string of the form '-r', '-d', etc. var c = key[1]; if (c in map) { var optionName = map[c]; options[optionName] = opt[key]; // assign the given value } else { error('option not recognized: ' + c, errorOptions || {}); } }); } return options; }
...
// If we are down by one argument and options starts with -, shift everything over.
[].unshift.call(arguments, '');
} else {
common.error('You must specify a file.');
}
}
options = common.parseOptions(options, {
'R': 'recursive',
'c': 'changes',
'v': 'verbose',
});
filePattern = [].slice.call(arguments, 2);
...
function _readFromPipe() { return state.pipedValue; }
...
//@ var str = cat(['file1', 'file2']); // same as above
//@ ```
//@
//@ Returns a string containing the given file, or a concatenated string
//@ containing the files if more than one file is given (a new line character is
//@ introduced between each file).
function _cat(options, files) {
var cat = common.readFromPipe();
if (!files && !cat) common.error('no paths given');
files = [].slice.call(arguments, 1);
files.forEach(function (file) {
if (!fs.existsSync(file)) {
...
function _register(name, implementation, wrapOptions) { wrapOptions = wrapOptions || {}; // If an option isn't specified, use the default wrapOptions = objectAssign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); if (shell[name] && !wrapOptions.overWrite) { throw new Error('unable to overwrite `' + name + '` command'); } if (wrapOptions.pipeOnly) { wrapOptions.canReceivePipe = true; shellMethods[name] = wrap(name, implementation, wrapOptions); } else { shell[name] = wrap(name, implementation, wrapOptions); } }
...
var common = require('./common');
var fs = require('fs');
common.register('cat', _cat, {
canReceivePipe: true,
});
//@
//@ ### cat(file [, file ...])
//@ ### cat(file_array)
//@
...
function ShellString(stdout, stderr, code) { var that; if (stdout instanceof Array) { that = stdout; that.stdout = stdout.join('\n'); if (stdout.length > 0) that.stdout += '\n'; } else { that = new String(stdout); that.stdout = stdout; } that.stderr = stderr; that.code = code; // A list of all commands that can appear on the right-hand side of a pipe // (populated by calls to common.wrap()) pipeMethods.forEach(function (cmd) { that[cmd] = shellMethods[cmd].bind(that); }); return that; }
...
// Dest is not existing dir, but multiple sources given
if ((!destExists || !destStat.isDirectory()) && sources.length > 1) {
common.error('dest is not a directory (too many sources)');
}
// Dest is an existing file, but -n is given
if (destExists && destStat.isFile() && options.no_force) {
return new common.ShellString('', '', 0);
}
sources.forEach(function (src) {
if (!fs.existsSync(src)) {
common.error('no such file or directory: ' + src, { continue: true });
return; // skip file
}
...
cat = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js
x27;), file);
});
shell.cd('..');
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
shell.echo('Error: Git commit failed');
shell.exit(1);
...
cd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
...
chmod = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
cp = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
...
dirs = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
echo = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
## Examples
```javascript
var shell = require('shelljs');
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
...
function error() { return common.state.error; }
...
//@
//@ Returns a string containing the given file, or a concatenated string
//@ containing the files if more than one file is given (a new line character is
//@ introduced between each file).
function _cat(options, files) {
var cat = common.readFromPipe();
if (!files && !cat) common.error('no paths given');
files = [].slice.call(arguments, 1);
files.forEach(function (file) {
if (!fs.existsSync(file)) {
common.error('no such file or directory: ' + file);
}
...
exec = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
shell.echo('Error: Git commit failed');
shell.exit(1);
}
```
## Global vs. Local
...
exit = function () {
/*
* this function will do nothing
*/
return;
}
...
## Examples
```javascript
var shell = require('shelljs');
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
...
find = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
grep = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
### Pipes
Examples:
```javascript
grep('foo', 'file1.txt', 'file2.txt').sed(/o/g, 'a').to('output.txt');
echo('files with o\'s in the name:\n' + ls().grep('o'));
cat('test.js').exec('node'); // pipe to exec() call
```
Commands can send their output to another command in a pipe-like fashion.
`sed`, `grep`, `cat`, `exec`, `to`, and `toEnd` can appear on the right-hand
side of a pipe. Pipes can be chained.
...
head = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
ln = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
ls = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
// Run external tool synchronously
...
mkdir = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
mv = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
popd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
pushd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
pwd = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
rm = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
...
sed = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
...
set = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
sort = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
}
var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8');
lines = lines.concat(contents.trimRight().split(/\r*\n/));
});
var sorted;
sorted = lines.sort(options.numerical ? numericalCmp : unixCmp);
if (options.reverse) {
sorted = sorted.reverse();
}
return sorted.join('\n') + '\n';
}
...
tail = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
tempdir = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
test = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
// $ cd ../../../..
// $ cp -RL 1 copy
var cyclecheck = fs.statSync(srcFile);
if (cyclecheck.isDirectory()) {
var sourcerealpath = fs.realpathSync(sourceDir);
var symlinkrealpath = fs.realpathSync(srcFile);
var re = new RegExp(symlinkrealpath);
if (re.test(sourcerealpath)) {
return true;
}
}
}
return false;
}
...
touch = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
uniq = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
n/a
which = function () {
var retValue = null;
state.currentCmd = cmd;
state.error = null;
state.errorCode = 0;
try {
var args = [].slice.call(arguments, 0);
// Log the command to stderr, if appropriate
if (config.verbose) {
console.error.apply(console, [cmd].concat(args));
}
// If this is coming from a pipe, let's set the pipedValue (otherwise, set
// it to the empty string)
state.pipedValue = (this && typeof this.stdout === 'string') ? this.stdout : '';
if (options.unix === false) { // this branch is for exec()
retValue = fn.apply(this, args);
} else { // and this branch is for everything else
if (isObject(args[0]) && args[0].constructor.name === 'Object') {
// a no-op, allowing the syntax `touch({'-r': file}, ...)`
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
args.unshift(''); // only add dummy option if '-option' not already present
}
// flatten out arrays that are arguments, to make the syntax:
// `cp([file1, file2, file3], dest);`
// equivalent to:
// `cp(file1, file2, file3, dest);`
args = args.reduce(function (accum, cur) {
if (Array.isArray(cur)) {
return accum.concat(cur);
}
accum.push(cur);
return accum;
}, []);
// Convert ShellStrings (basically just String objects) to regular strings
args = args.map(function (arg) {
if (isObject(arg) && arg.constructor.name === 'String') {
return arg.toString();
}
return arg;
});
// Expand the '~' if appropriate
var homeDir = getUserHome();
args = args.map(function (arg) {
if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') {
return arg.replace(/^~/, homeDir);
}
return arg;
});
// Perform glob-expansion on all arguments after globStart, but preserve
// the arguments before it (like regexes for sed and grep)
if (!config.noglob && options.allowGlobbing === true) {
args = args.slice(0, options.globStart).concat(expand(args.slice(options.globStart)));
}
try {
// parse options if options are provided
if (isObject(options.cmdOptions)) {
args[0] = parseOptions(args[0], options.cmdOptions);
}
retValue = fn.apply(this, args);
} catch (e) {
/* istanbul ignore else */
if (e.msg === 'earlyExit') {
retValue = e.retValue;
} else {
throw e; // this is probably a bug that should be thrown up the call stack
}
}
}
} catch (e) {
/* istanbul ignore next */
if (!state.error) {
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
console.error('ShellJS: internal error');
console.error(e.stack || e);
process.exit(1);
}
if (config.fatal) throw e;
}
if (options.wrapOutput &&
(typeof retValue === 'string' || Array.isArray(retValue))) {
retValue = new ShellString(retValue, state.error, state.errorCode);
}
state.currentCmd = 'shell.js';
return retValue;
}
...
```
## Examples
```javascript
var shell = require('shelljs');
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
...