Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Development Tools Git Basics Getting Started With Git Working With Git Repositories

Mathew Kurian
Mathew Kurian
4,698 Points

How do you run multi-stage commands on Terminal?

So I've been playing around with Terminal on my Macbook and seeing what I could do. I was wondering whether you could take the output one complex command and use it as the input for another.

For example: Say I ran { ls -aFR | grep "." | grep "/" | grep "Witcher" }. This basically looks for hidden directories in your file system and lists them out. If you get like 10 files as the output is there anyway to remove all of them with a single command? Instead of typing out and "rm" followed by each path name?

Have you tried using that command as input for rm? something like: rm < ls -aFR | grep "." | grep "/" | grep "Witcher"

Mathew Kurian
Mathew Kurian
4,698 Points

I was not aware we could do that. Makes sense though since ">" means we take previous output as input.

3 Answers

Brent Petit
Brent Petit
7,860 Points

Let me start by saying, be really-really careful with scripted rm operations. if you don't filter out enough files you'll delete stuff you didn't intend to. That being said, you can start by building the output of grep lines into a single line by piping it to 'xargs'.

ls -aFR | grep "." | grep "/" | grep "Witcher" | xargs

if you wanted to use that line as arguments to rm you could do something like this. With backticks...

rm `ls operation | xargs`

This will evaluate everything between the backticks first, resulting in the string of filenames which will then be used as the argument to rm.

I would also recommend looking at the find command. This can be used to search for files. Then the -exec option can be used to run an rm, or whatever command you desire, against the matching filenames.

Mathew Kurian
Mathew Kurian
4,698 Points

I tried doing it with the "find" command first, but it was hard to use and a little unwieldy. What does "operation" in the second command do? And also is it possible to create an alias of this command? So that every time you type in that "alias" it executes the desired command?

Brent Petit
Brent Petit
7,860 Points

Sorry if my example wasn't so clear. "Operation" was intended to be shorthand for the ls command you wanted to run. So in your case you would actually run...

rm `ls -aFR | grep "." | grep "/" | grep "Witcher" | xargs`

Of course, I would highly recommend running the ls operation without the rm first to make sure you have the file list you desire.

Mathew Kurian
Mathew Kurian
4,698 Points

Hey so I did that, but it treats the whole thing as a single directory. And it says "no such file or directory".

I also tried the "<" operator as Preston said above, but that didn't work either. Am I doing something wrong? Is "xargs" a Linux only command? Cause I'm doing this in Terminal on my Macbook Pro.

Brent Petit
Brent Petit
7,860 Points

Make sure you are using backticks ( the key to the left of the 1 key) around your original ls command. It sounds like you were using single and double quotes.

And xargs is present on Macs. Type...

man xargs

and you should see instructions on the xargs command.

I would encourage Brent's statement on using find in stead of other commands. Agreed that it is a bit to get use to, but it extremely useful in the long term.

It'll allow you to first check what you are about to remove then execute.

An example:

find -E ./ -regex "(\.|/|Witcher)" -exec ls -ld {} >> mydelfile \;

# Confirm the list, and now re-run with rm 

find -E ./ -regex "(\.|/|Witcher)" -exec rm -rf {} \;

The above is just an example and likely does not find the exact files you re looking for. The -E provides extended regex capabilities.

Mathew Kurian
Mathew Kurian
4,698 Points

Can you please explain your command? I don't understand what regex is, or the "-exec" option, ld, and the {}.