Linux HowTo: which files can be deleted to save space

Original Source Link

I have scanned my C drive with TreeSize tool.
Here is a screenshot.
tree size tool scan

I want to know which files I can delete to save space.
I am on Windows 10.

The safest general advice is simply to use the Disk Cleanup utility included with Windows.

This will clear the standard things and will not damage your system.

Besides this, what can be deleted will depend on what is on your computer.

Based only on the screenshot (which doesn’t tell us much) a lot of your disk space is used up in your User folders, which is good. Those are mostly files you placed yourself and so can move or remove without damaging the system.

Your space is taken up in USERS (normal) and page / hiber files. Do not delete the latter as they have been set up at some point and needed.

Windows 10 1909 and beyond, set up storage delete. Start, System, Storage and set up thresholds and days.

In C:UsersyouAppDataLocalTemp, delete what you can (most will delete, some are in use).

In C:WindowsTemp, same as above. If Windows tells you that you need permissions, grant permission to open the folder.

Now use Disk Cleanup. When it starts, select Clean up System Folders, and it runs again. Then select All Items in the selection box, OK, and allow it to finish. If it wants to delete Windows.old and your system is working properly, allow that.

When all is done, do a final restart and check disk space now versus before.

If you need more space relief, look in document, pictures, movies and like places and back old files off to an external USB Hard or SSD Drive.

Tagged : / / /

Making Game: which files can be deleted to save space

Original Source Link

I have scanned my C drive with TreeSize tool.
Here is a screenshot.
tree size tool scan

I want to know which files I can delete to save space.
I am on Windows 10.

The safest general advice is simply to use the Disk Cleanup utility included with Windows.

This will clear the standard things and will not damage your system.

Besides this, what can be deleted will depend on what is on your computer.

Based only on the screenshot (which doesn’t tell us much) a lot of your disk space is used up in your User folders, which is good. Those are mostly files you placed yourself and so can move or remove without damaging the system.

Your space is taken up in USERS (normal) and page / hiber files. Do not delete the latter as they have been set up at some point and needed.

Windows 10 1909 and beyond, set up storage delete. Start, System, Storage and set up thresholds and days.

In C:UsersyouAppDataLocalTemp, delete what you can (most will delete, some are in use).

In C:WindowsTemp, same as above. If Windows tells you that you need permissions, grant permission to open the folder.

Now use Disk Cleanup. When it starts, select Clean up System Folders, and it runs again. Then select All Items in the selection box, OK, and allow it to finish. If it wants to delete Windows.old and your system is working properly, allow that.

When all is done, do a final restart and check disk space now versus before.

If you need more space relief, look in document, pictures, movies and like places and back old files off to an external USB Hard or SSD Drive.

Tagged : / / /

Code Bug Fix: generic tree node structure: problem freeing the child nodes

Original Source Link

Based on this GenericTree I have implemented the following generic tree node structure:

type
  TTreeNode<T>=class
  private
    procedure FreeChildNodes; 
    procedure RemoveMyselfFromParentChildNodesList;
    function GetIndexInParentChildNodesList: Integer;
  public
    NodeData: T;
    ChildNodes: TList<TTreeNode<T>>;
    ParentNode: TTreeNode<T>;
    constructor Create(const AParentNode: TTreeNode<T>); overload;
    destructor Destroy; override;
  end;

implementation

constructor TTreeNode<T>.Create(const AParentNode: TTreeNode<T>);
begin
  inherited Create;
  ParentNode:=AParentNode;
  ChildNodes:=TList<TTreeNode<T>>.Create;
end;

destructor TTreeNode<T>.Destroy;
begin
  FreeChildNodes;
  RemoveMyselfFromParentChildNodesList;
  ChildNodes.Free;
  inherited;
end;

procedure TTreeNode<T>.FreeChildNodes;
var
  i: Integer;
begin
  for i := ChildNodes.Count-1 downto 0 do
  begin
    ChildNodes[i].Free;
  end;
  ChildNodes.Clear;
end;

function TTreeNode<T>.GetIndexInParentChildNodesList: Integer;
var
  i: Integer;
begin
  Result:=-1;
  if ParentNode<>nil then
  begin
    Result:=ParentNode.ChildNodes.IndexOf(Self);
  end;
end;

procedure TTreeNode<T>.RemoveMyselfFromParentChildNodesList;
begin
  if ParentNode<>nil then
  begin
    ParentNode.ChildNodes.Delete(GetIndexInParentChildNodesList);
  end;
end;

This is working fine.

Now I would like to create an descendant class with a specific object type.

The object type is:

type
  TMyObject=class
  public
    Value: string;
    constructor Create; override;
    destructor Destroy; override;
  end;

And the new descendant class:

type
  TMyTreeNode=class(TTreeNode<TMyObject>)
  private
  public
    constructor Create(const AParentNode: TMyTreeNode); overload;
    destructor Destroy; override;
  end;

implementation

constructor TMyTreeNode.Create(const AParentNode: TMyTreeNode);
begin
  inherited Create(AParentNode);
  NodeData:=TMyObject.Create;
end;

destructor TMyTreeNode.Destroy;
begin
  NodeData.Free;
  inherited;
end;

When I free a TMyTreeNode with TMyTreeNode.Destroy the inherited TTreeNode<T>.Destroy is called to free the ChildNodes recursively. The problem is that all ChildNodes are then freed with TTreeNode<T>.Destroy and therefore the TMyObjects are not freed leaving a memory leak.

I also tried to use TObjectList instead of TList for the ChildNodes. However the TObjectList seems to destroy itself before I can free the child nodes.

How to solve this problem?

You could use:

procedure TTreeNode<T>.FreeChildNodes;
var
  i: Integer;
begin
  for i := ChildNodes.Count-1 downto 0 do
  begin
    ChildNodes[i].NodeData.free;
    ChildNodes[i].Free;
  end;
  ChildNodes.Clear;
end;

There’s no need to override the destructor if it only affects fields of the parent type. In your case the TMyTreeNode.Destroy only frees the NodeData from the parent, so you might just as well do it in the TTreeNode<T>.FreeChildNodes procedure.

Tagged : / /

Code Bug Fix: What is this subset of a n-ary tree called?

Original Source Link

Given an n-ary tree, put the root node in a list. Repeat the following procedure:

Take an arbitrary node in this list and replace it with its immediate child nodes in the tree.

At each step, the resulting list represents a subset of the three with some interesting properties:

  • No two nodes in the list are direct or indirect descendants of each other
  • Any path that I walk from the root node, I will end up at a node in this list

Is there a name for this kind of subset of an n-ary tree?

enter image description here

Tagged : / /

Ubuntu HowTo: Explain difference in non-hidden file count when using Nautilus vs. using other tools such as tree and how to independently calculate former count?

Original Source Link

I recently have been backing up my files from a laptop and as part of that have opted to move a folder that at first seemed to be of size 107.6 GB from one hard drive to another. As I was copying, I noticed that a dialog box showed up saying there are far more files than I thought there were — about 275,000 as opposed to about 160,000. Later, I realized that this has to do with dot files (i.e. hidden files). I wanted to know that when I finished copying that the size and number of files for source and destination matched. Well, I was able to use Nautilus folder dialogs to show that the non-hidden item counts and non-hidden item sizes for source and for destination were the same.

However, I would like to figure out how to arrive at those non-hidden item absolute numbers independently.

My questions are: (1) is there a conceptual explanation for a discrepancy between non-hidden item counts from Nautilus and from e.g. tree; and (2) how do we use existing tools other than Nautilus to get the results for non-hidden item count given by Nautilus?


All (including hidden) items

I have tried tree -a inside the directory we care about, which gives:
28949 directories, 246973 files

This means tree -a gives 275,922 items total.

Nautilus gives 275,923 items total, assuming I have toggled on the “show hidden files” option for Nautilus; this is a match, since it is okay for us to add one to the result from tree -a.

All non-hidden items

I have tried tree inside the directory we care about, which gives:
14860 directories, 146703 files

This means tree gives 161,563 non-hidden items total.

Nautilus gives 160,829 non-hidden items total, assuming I have toggled off the “show hidden files” option for Nautilus; also, even after adding one to the result from tree, the two counts from tree and Nautilus are slightly different.


I understand that Nautilus behaves (when “show hidden files” is off) by excluding dot-folders and dot-files and any (possibly non-dot folder or file) items that are recursively in some dot-folder. For small examples that I have crafted, results from tree and from Nautilus seem to match up.

Again, How do I explain the discrepancy for non-hidden item counts? It is worth noting that I am interested in recursive counts. Also, I am using Ubuntu 20.04 and the file system that the files are at is NTFS. I would provide the experimental data that I am using, but it is not so convenient to pull out non-sensitive data and simultaneously preserve this discrepancy for non-hidden item count.

Also, I have come across another AskUbuntu post that touches on Nautilus and tree, but it doesn’t explain why there is a discrepancy when we avoid using the -a option:
Why do I see a difference in file count between Nautilus and find?


Here are some pictures that, admittedly, do not really add any new details.

(I have temporarily named the folder in question “A”.)

  1. All (including hidden) items via Nautilus:

  2. All non-hidden items via Nautilus:

  3. All (including hidden) items via tree -a:

  4. All non-hidden items via tree:


Again, if there is some other way besides using tree to count non-hidden files recursively in current folder and in subfolders s.t. we match up with Nautilus again, that would also be appreciated.

It seems that some approaches that use find or ls may be susceptible to special characters in folder or file names (e.g. new line). The previously provided AskUbuntu post is relevant for this detail. Also, here is a Unix StackExchange post with a response that mentions a find-based approach s.t. regular files in hidden folders are specifically are considered hidden as well in a count (just as we assume Nautilus and tree do), but the numbers don’t match up perfectly, still:
https://unix.stackexchange.com/questions/18227/how-to-recursively-list-all-hidden-files-and-directories

The response that we mention is here:
https://unix.stackexchange.com/a/18228


Thanks,
Brian


Edit: The hard drive that these documents are stored on is a freshly formatted drive. The operating system is a freshly installed instance of Ubuntu Desktop 20.04. As far as I know, I do not have any extra processes interacting with the directory that I would like to measure number of non-hidden items for. Again, by non-hidden item, I mean an item that is not recursively in some dot-folder, assuming the main directory is not hidden. Again, is there a good explanation for why I get different results for Nautilus and for e.g. tree when counting non-hidden documents in a folder and is there a way to independently calculate the non-hidden item counts given by Nautilus?

Tagged : / / / /

Server Bug Fix: What should a Traversable instance look like for a Tree datatype with a nested Maybe value?

Original Source Link

I have a Haskell exam in three days, so I thought I should practice a little and pulled up past exams, one of which features the following Tree datatype:

data Tree a = Leaf1 a | Leaf2 a a | Node (Tree a) (Maybe (Tree a)) deriving (Eq, Ord, Show)

It didn’t seem that challenging at first, but then I realized I have to write a Traversable instance for this Tree. Dealing with the leaves were easy enough:

instance Traversable Tree where
  traverse f (Leaf1 a)   = Leaf1 <$> f a
  traverse f (Leaf2 a b) = Leaf2 <$> f a <*> f b

However, I started running into problems with the Node.

  traverse f (Node t Nothing)  = Node <$> traverse f t <*> Nothing
  traverse f (Node l (Just r)) = Node <$> traverse f l <*> Just (traverse f r)

Naturally, these don’t work, and I can’t wrap my head around what should come after the second <*>. I tried using holes, but the messages given to me by ghci didn’t help much (I get that the problem is with types, but I have no idea how I’m supposed to fix it).

Here’s the error message I got when I tried to compile it:

* Couldn't match type `f' with `Maybe'
  `f' is a rigid type variable bound by
    the type signature for:
      traverse :: forall (f :: * -> *) a b.
                  Applicative f =>
                  (a -> f b) -> Tree a -> f (Tree b)
    at exam.hs:92:3-10
  Expected type: f (Maybe (Tree b))
    Actual type: Maybe (Maybe (Tree b))
* In the second argument of `(<*>)', namely `Nothing'
  In the expression: Node <$> traverse f t <*> Nothing
  In an equation for `traverse':
      traverse f (Node t Nothing) = Node <$> traverse f t <*> Nothing
* Relevant bindings include
    f :: a -> f b (bound at exam.hs:94:12)
    traverse :: (a -> f b) -> Tree a -> f (Tree b)
      (bound at exam.hs:92:3)
   |
94 |   traverse f (Node t Nothing)  = Node <$> traverse f t <*> Nothing
   |                                                            ^^^^^^^

Could someone please give me some pointers or a possible fix for this issue?

traverse lets you apply a “function with an effect” to every “slot” of a data structure, maintaining the structure’s shape. It has the type:

traverse :: Applicative f => (a -> f b) -> t a -> f (t b)

It relies crucially on the fact that the type of the “effects” is an Applicative. What operations does Applicatve provide?

  • it lets us lift pure functions and apply them to effectful actions with <$>.
  • it lets us combine effectful actions with (<*>) :: f (a -> b) -> f a -> f b. Notice that the second parameter is an effectful action, not a pure value.
  • it lets us take any pure value and put it in an effectful context, using pure :: a -> f a.

Now, when the node has a Nothing, there’s no effect to perform because there aren’t any values, but the <*> still requires an effectful action on the right. We can use pure Nothing to make the types fit.

When the node has a Just t, we can traverse the subtree t of type Tree a with the function a -> f b and end up with an action f (Tree b). But the <*> is actually expecting an f (Maybe (Tree b)). The lifted Node constructor makes us expect that. What can we do?

The solution is to lift the Just constructor into the action using <$>, which is another name for fmap.

Notice that we haven’t changed the overall “shape” of the value: the Nothing is still Nothing, the Just is still Just. The structure of the subtrees didn’t change either: we traversed them recursively but didn’t modify them otherwise.

The short answer is that you need to use traverse to get inside the Maybe.

The Traversable and Foldable instances for a type often have a similar structure to its Functor instance. Whereas fmap maps a pure function over a structure, combining the results back up with the pure constructors:

instance Functor Tree where
  fmap f (Leaf1 a) = Leaf1 (f a)
  fmap f (Leaf2 a1 a2) = Leaf2 (f a1) (f a2)
  fmap f (Node ta mta) = Node (fmap f ta) (fmap (fmap f) mta)

Note the (fmap (fmap f) mta): the outer fmap maps over the Maybe, while the inner one maps over the Tree:

(fmap
  :: (Tree a -> Tree b)
  -> Maybe (Tree a) -> Maybe (Tree b))
  ((fmap
    :: (a -> b)
    -> Tree a -> Tree b)
    f)
  mta

traverse instead maps an effectful function over the structure, and correspondingly lifts the constructors into Applicative with the <$> and <*> operators:

instance Traversable Tree where
  traverse f (Leaf1 a) = Leaf1 <$> f a
  traverse f (Leaf2 a1 a2) = Leaf2 <$> f a1 <*> f a2
  traverse f (Node ta mta) = Node <$> traverse f ta <*> traverse (traverse f) mta

Again, notice that we must traverse the Maybe, and within that, traverse the Tree, but instead of a pure function a -> b, we just have an effectful function a -> f b, given Applicative f:

(traverse
  :: (Tree a -> f (Tree b))
  -> Maybe (Tree a) -> f (Maybe (Tree b)))
  ((traverse
    :: (a -> f b)
    -> Tree a -> f (Tree b))
    f)
  mta

Likewise, foldMap has a similar structure, but instead of reconstructing the data type, it combines results using a Monoid instance:

instance Foldable Tree where
  foldMap f (Leaf1 a) = f a
  foldMap f (Leaf2 a1 a2) = f a1 <> f a2
  foldMap f (Node ta mta) = foldMap f ta <> foldMap (foldMap f) mta

And here’s a simple example usage of traverse:

> traverse ( x -> print x *> pure (x + 1)) (Node (Leaf1 10) (Just (Leaf2 20 30)))
10
20
30
Node (Leaf1 11) (Just (Leaf2 21 31))

With the DeriveFoldable, DeriveFunctor, and DeriveTraversable extensions, you may add a deriving (Foldable, Functor, Traversable) clause to a data type and use the -ddump-deriv flag of GHC to see the generated code.

Tagged : / / /

Code Bug Fix: How to convert nested foreach for category tree into recursion? [closed]

Original Source Link

I need to make this nested loop into recursion because I don’t know how much depth will the category tree have.

PHP code:

$categories = [];
foreach ($category_tree as $category_1) {
    $categories[$category_1['id_category']] = $category_1['name'];
    if (count($category_1['children'])) {
        foreach ($category_1['children'] as $category_2) {
            $categories[$category_2['id_category']] = $category_1['name'] . ' > ' . $category_2['name'];
            if (count($category_2['children'])) {
                foreach ($category_2['children'] as $category_3) {
                    $categories[$category_3['id_category']] = $category_1['name'] . ' > ' . $category_2['name'] . ' > ' . $category_3['name'];
                    if (count($category_3['children'])) {
                        foreach ($category_3['children'] as $category_4) {
                            $categories[$category_4['id_category']] = $category_1['name'] . ' > ' . $category_2['name'] . ' > ' . $category_3['name'] . ' > ' . $category_4['name'];
                            if (count($category_4['children'])) {
                                foreach ($category_4['children'] as $category_5) {
                                    $categories[$category_5['id_category']] = $category_1['name'] . ' > ' . $category_2['name'] . ' > ' . $category_3['name'] . ' > ' . $category_4['name'] . ' > ' . $category_5['name'];
                                    if (count($category_4['children'])) {

                                    }
                                } 
                            }
                        } 
                    }
                } 
            }
        }
    }
}

And the result should be like this:

Array
(
  [2] => Home
  [3] => Home > Clothes
  [4] => Home > Clothes > Men
  [6] => Home > Women's Clothing
  [7] => Home > Women's Clothing > Stationery
  [10] => Home > Women's Clothing > Jackets
  [88] => Home > Women's Clothing > Jackets > Women's Sports Teams
)

Probably this, but since you didn’t provide the input, I couldn’t test it.

function get_category_map(&$tree, &$out, $pre = '')
{
    foreach ($tree as &$cat)
    {
        $out[$cat['id_category']] = $pre . $cat['name'];
        if (count($cat['children']))
            get_category_map($cat['children'], $out, "{$pre}{$cat['name']} > ");
    }
}

$categories = [];
get_category_map($category_tree, $categories);
print_r($categories);

Tagged : / / /

Linux HowTo: Hierarchy path: Find orphans (children without parents)

Original Source Link

I have hierarchy path values:

FLEET
FLEET  AIR SYSTEM
FLEET  AIR SYSTEM  COMPRESSOR - DRYER
FLEET  AIR SYSTEM  VALVES
FLEET  AIR SYSTEM  RESERVOIRS
FLEET  AIR SYSTEM  HOSES - LINES - FITTINGS

FLEET  ATTACHMENTS
FLEET  ATTACHMENTS  BLADE
FLEET  ATTACHMENTS  SALTER
FLEET  ATTACHMENTS  BROOM
FLEET  ATTACHMENTS  MOWER
FLEET  ATTACHMENTS  HITCH
FLEET  ATTACHMENTS  MISCELLANEOUS

["FLEET  BODY EXTERIOR" --> parent is missing]
FLEET  BODY EXTERIOR  BODY PANELS
FLEET  BODY EXTERIOR  WIPERS
FLEET  BODY EXTERIOR  MIRRORS
FLEET  BODY EXTERIOR  ACCESSORIES
FLEET  BODY EXTERIOR  ACCESSORIES  CATEGORY 1
FLEET  BODY EXTERIOR  ACCESSORIES  CATEGORY 2

I am trying to find children that don’t have parents.

For example, I want to indicate that the parent in row #16 is missing for rows #17-20.

Is there a way to do this in Excel?

A solution:

=IF(COUNTIF(A:A,LEFT(A1,FIND(CHAR(1),SUBSTITUTE(A1,"",CHAR(1),LEN(A1)-LEN(SUBSTITUTE(A1,"",""))))-2))=1,"","Error")

enter image description here

The formula flags hierarchy paths that are orphaned (children without parents).


Explanation:

1) Remove the lowest level from the hierarchy path:

=LEFT(A1,FIND(CHAR(1),SUBSTITUTE(A1,"",CHAR(1),LEN(A1)-LEN(SUBSTITUTE(A1,"",""))))-2)

2) Use countif to determine if the value from step #1 exists in column A.

In other words, check to see if that parent exists.

=IF(COUNTIF(   ...Step #1...   )=1,"","Error")

Tagged : / / /

Making Game: Hierarchy path: Find orphans (children without parents)

Original Source Link

I have hierarchy path values:

FLEET
FLEET  AIR SYSTEM
FLEET  AIR SYSTEM  COMPRESSOR - DRYER
FLEET  AIR SYSTEM  VALVES
FLEET  AIR SYSTEM  RESERVOIRS
FLEET  AIR SYSTEM  HOSES - LINES - FITTINGS

FLEET  ATTACHMENTS
FLEET  ATTACHMENTS  BLADE
FLEET  ATTACHMENTS  SALTER
FLEET  ATTACHMENTS  BROOM
FLEET  ATTACHMENTS  MOWER
FLEET  ATTACHMENTS  HITCH
FLEET  ATTACHMENTS  MISCELLANEOUS

["FLEET  BODY EXTERIOR" --> parent is missing]
FLEET  BODY EXTERIOR  BODY PANELS
FLEET  BODY EXTERIOR  WIPERS
FLEET  BODY EXTERIOR  MIRRORS
FLEET  BODY EXTERIOR  ACCESSORIES
FLEET  BODY EXTERIOR  ACCESSORIES  CATEGORY 1
FLEET  BODY EXTERIOR  ACCESSORIES  CATEGORY 2

I am trying to find children that don’t have parents.

For example, I want to indicate that the parent in row #16 is missing for rows #17-20.

Is there a way to do this in Excel?

A solution:

=IF(COUNTIF(A:A,LEFT(A1,FIND(CHAR(1),SUBSTITUTE(A1,"",CHAR(1),LEN(A1)-LEN(SUBSTITUTE(A1,"",""))))-2))=1,"","Error")

enter image description here

The formula flags hierarchy paths that are orphaned (children without parents).


Explanation:

1) Remove the lowest level from the hierarchy path:

=LEFT(A1,FIND(CHAR(1),SUBSTITUTE(A1,"",CHAR(1),LEN(A1)-LEN(SUBSTITUTE(A1,"",""))))-2)

2) Use countif to determine if the value from step #1 exists in column A.

In other words, check to see if that parent exists.

=IF(COUNTIF(   ...Step #1...   )=1,"","Error")

Tagged : / / /

Linux HowTo: Display dirs tree based on a file content

Original Source Link

$ find ./ | tac

./dir1/file -> "abc"
./dir1
./dir2/file - > "abc"
./dir2
./dir3/file -> "xyz"
./dir3/dir3_1/file  - > "abc"
./dir3/dir3_1
./dir3

or

$ tree

├── dir1
│   └── file -> "abc"
├── dir2
│   └── file -> "abc"
└── dir3
    ├── dir3_1
    │   └── file -> "abc"
    └── file -> "xyz"

I need to display a dirs tree (without files) only these that have a “file” file containing “abc” value.

I know there is a command tree -P 'file*' to filter the tree by filename, maybe there is also a method to filter the tree by “grepping” a content.

I also came up with the idea to do something like this (of course it doesn’t work):

   $(find ./ -type f -exec grep abc {} +;) | tree -d

and somehow send flat find results to to tree command.

Using tree --fromfile

In my Debian 10 I have tree v1.8.0. It supports --fromfile.

--fromfile
Reads a directory listing from a file rather than the file-system. Paths provided on the command line are files to read from rather than directories to search. The dot (.) directory indicates that tree should read paths from standard input.

This way I can feed tree with output from find or grep -rl:

grep -rl abc | tree -d --fromfile .

Problems:

  • . will be reported even if there is no matching file at all.

  • If tree reads /foo/whatever or foo/whatever then foo will be reported as a subdirectory of .. Similarly with ./whatever: . will be reported as an additional level named .. So if you use grep -rl abc /foo, grep -rl abc ., find /foo or find . then the results may not entirely meet your formal expectations.

  • Filenames with newlines will confuse tree. Using grep -Z or find -print0 is not an option because there is no corresponding switch for tree.

  • A matching file inside foo/bar/ together with a matching file inside foo/ will generate the same output as the matching file in foo/bar/ alone. If you see the foo/bar branch then you cannot know if there’s a matching file in foo/. This is a flaw in your specification.


Alternative approach

The following code doesn’t use --fromfile. It fixes some of the above problems but it’s slower.

#!/bin/sh

tmp="$(mktemp -d)"
[ "$?" -eq 0 ] || exit 2
trap 'rm -r "$tmp"' INT TERM EXIT
dir="${2:-.}"

cd "$dir" || exit 1

find . -type f -exec grep -q "$1" {} ; -exec sh -c '
   cd "$1" || exit 1
   shift 1
   for d; do
      mkdir -p "top/$(dirname "$d")"
   done
' sh-find "$tmp" {} +

cd "$tmp" || exit 1
[ -d "top" ] || exit 0
printf "%sn" "$dir"
tree -d --noreport "top" | tail -n +2

Usage: scriptname pattern /path/to/dir or scriptname pattern (then . is the default directory).

The general procedure is as follows:

  1. Create a temporary directory.
  2. For each matching file create directories inside the temporary directory, so the relative paths correspond. This way the desired directory structure is built inside the temporary directory.
  3. Use tree -d in the temporary directory (adjusting the output, so the original directory path replaces the temporary top node).
  4. Remove the temporary directory.

Note a directory named top will be crated if and only if there’s at least one match. This way we can tell if there was a match. Empty output (with exit status 0) indicates there was no match at all.

Tagged : / / / /