How get ASCII characters similar to output of the linux command 'tree'?
Asked Answered
W

4

12

Is there a way to print the ASCII charachter '├── ' and '└──' using a bash or perl script? I want it be exactly like the output of 'tree'.

[root@localhost www]# tree -L 1
.
├── cgi-bin
├── error
├── html
└── icons
Washhouse answered 21/2, 2014 at 3:4 Comment(0)
F
4
echo -e "\0342\0224\0224\0342\0224\0200\0342\0224\0200 \033[01"
Fed answered 21/2, 2014 at 3:19 Comment(2)
Thanks. This worked for me i got the char '└──'. but how do i print '├── ' ?Washhouse
echo -e "\0342\0224\0234\0342\0224\0200\0342\0224\0200"Fed
S
6

Using Unicode specific character in

There are 3-4 different answers here, some tips and samples...

1. Using special character directly into UTF8 script.

HorizT='├'
HLine='─'
echo $HorizT$HLine$HLine
├──

2. Finding character value from output sample

As you are speaking tree as output sample, U could run something like

tree / | sed -ne '2{p;q}'
├── bin

tree / | sed -ne '2{p;q}' | od -An -t o1
342 224 234 342 224 200 342 224 200 040 142 151 156 012

To output your reference as octal values.

Knowing that Unicode use variable number of bytes, that your reference string hold 3 unicode characters, there look like 3 group of 3 values, begining by 342.

So you could try:

printf "\342\224\234\n"
├

printf -v HorizontalT "\342\224\234"
printf -v Hline "\342\224\200"

echo $HorizontalT$Hline$Hline$Hline
├───

2.b Same in pure bash:

If you try to cut'n paste this in a terminal:

declare -A shown='()'                  # Array list of already shown characters.
while IFS= read -r line; do                      # For each line in tree output,
    for ((i=0; i<${#line}; i++)); do          # For each character in each line,
        [[ ${line:i:1} == \  ]] && break       # Stop reading line at 1st space!
        if ! [[ -v shown["${line:i:1}"] ]]; then         # If not already shown,
            LANG=C printf -v char %q "${line:i:1}" # Store C printable in $char,
            [[ ${char#\\} == "${line:i:1}" ]] ||    # If printable != character,
                printf 'Char: \47%s\47 => %s\n' "${line:i:1}" "$char"   # print,
            shown["${line:i:1}"]=yes        # Add character to shown array list.
        fi
    done                                                           # Line done,
done < <(tree )    # Done! All this are taking input from tree command's output. 

You must see:

Char: '├' => $'\342\224\234'
Char: '─' => $'\342\224\200'
Char: '│' => $'\342\224\202'
Char: ' ' => $'\302\240'
Char: '└' => $'\342\224\224'

Notes:

  • When running this, your current directory must have at least 1 sub directory, which are not empty, for showing complete output.
  • Execution time will depend on tree size! ( You may have to wait for the last '└' ;-).

3. Searching for specific character by using charmap

You could use dedicated Unicode browser, like charmap under Debian Gnome GNU/Linux:

GNOME Character Map

Browse and find your character, then on second tab: Character Details:

charmap detail

You may read Various Useful Representations -> octal escaped:

printf '\342\224\234\n'
├

3+. Printing Unicode fonts using printf

Once you know unicode value, you could use printf for creating variable:

printf -v char '\U251C'
echo $char
├

From there, after some brainstorm:

string=
for i in 0 2 16 24 {12..60..8} ;do
    printf -v r '\\U25%02X' $i
    printf -v char "$r"
    string+="$char "
done
echo "$string"
─ │ ┐ ┘ ┌ └ ├ ┤ ┬ ┴ ┼ 

Or

string=
for i in {80..108} ;do
    printf -v r '\\U25%02X' $i
    printf -v char "$r"
    string+="$char "
done
echo "$string"
═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ 

4. Final bash function

Strictly answering SO request:

I want it be exactly like the output of 'tree'.

Here is a function:

tree-L1() { 
    local _i indent=0 entry root=${1:-.};
    local -i dirs files;
    [[ $1 == -i ]] && indent=$2 && shift 2;
    echo "$root";
    . <(cd "$root";set -- *;echo ${@@A});
    printf -v indent '%*s' "$indent" '';
    for ((_i=1; _i<=$#; _i++))
    do
        entry=${!_i};
        [[ -d $root/$entry ]] && dirs+=1 || files+=1;
        [[ -L $root/$entry ]] && printf -v entry '%s -> %s' "${!_i}" "$(
            readlink "$root/${!_i}")";
        if ((_i==$#)); then
            printf '%b%b%b%b %s\n' "${indent// /\\U2502   }" \
                \\U2514 \\U2500{,} "$entry";
        else
            printf '%b%b%b%b %s\n' "${indent// /\\U2502   }" \
                \\U251C \\U2500{,} "$entry";
        fi;
    done;
    printf '\n%d directories, %d files\n' $dirs $files
}

Then you could try to compare:

diff <(tree-L1 /etc) <(tree -L 1 /etc)

may output nothing, as there's no differences between regular tree -L 1 output and my function's ouptput!! Or

diff --width 80 -y <(tree-L1 /etc) <(tree -L 1 /etc)

5. Browse Unicode table by character name

Please have a look at Is there a (linux) terminal character picker? on SuperUser, I've posted a little Python unicode library:

./dumpUnicode | grep 'BOX DRAWINGS LIGHT.*\(HORI\|VERT\)'
\U002500: '─' BOX DRAWINGS LIGHT HORIZONTAL
\U002502: '│' BOX DRAWINGS LIGHT VERTICAL
\U002504: '┄' BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL
\U002506: '┆' BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL
\U002508: '┈' BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL
\U00250A: '┊' BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL
\U00251C: '├' BOX DRAWINGS LIGHT VERTICAL AND RIGHT
\U002524: '┤' BOX DRAWINGS LIGHT VERTICAL AND LEFT
\U00252C: '┬' BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
\U002534: '┴' BOX DRAWINGS LIGHT UP AND HORIZONTAL
\U00253C: '┼' BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
\U00254C: '╌' BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL
\U00254E: '╎' BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL
\U01FBAF: '🮯' BOX DRAWINGS LIGHT HORIZONTAL WITH VERTICAL STROKE

5+ Extracting specials chars from tree outputs, with full descriptions

And with previous script, 1st creating a associative array u8Table:

declare -A u8Table='()'
while IFS=\  read -r cod char dsc; do
    char="${char#\'}" char="${char%\'}"
    u8Table["$char"]="$cod $dsc"
done < <(dumpUnicode | grep -v '^.U0000[2-7]')

Then

declare -A shown='()'
while IFS= read -r line; do
    for ((i=0; i<${#line}; i++)); do
        [[ ${line:i:1} == \  ]] && break
        if ! [[ -v shown["${line:i:1}"] ]]; then
            LANG=C printf -v char %q "${line:i:1}"
            [[ ${char#\\} == "${line:i:1}" ]] ||
                 printf 'Char: \47%s\47 => %-16s %s\n' \
                     "${line:i:1}" "$char" "${u8Table["${line:i:1}"]}"
            shown["${line:i:1}"]=yes
        fi
    done
done < <(tree)
Char: '├' => $'\342\224\234'  \U00251C: BOX DRAWINGS LIGHT VERTICAL AND RIGHT
Char: '─' => $'\342\224\200'  \U002500: BOX DRAWINGS LIGHT HORIZONTAL
Char: '│' => $'\342\224\202'  \U002502: BOX DRAWINGS LIGHT VERTICAL
Char: ' ' => $'\302\240'      \U0000A0: NO-BREAK SPACE
Char: '└' => $'\342\224\224'  \U002514: BOX DRAWINGS LIGHT UP AND RIGHT

6. Further...

Have a look at Playing with UTF8 in bash

Sedlik answered 29/3, 2021 at 6:52 Comment(0)
E
5

They look to be a part of the extended ascii codes. You can see them here http://www.asciitable.com/

Also available at the Unicode table here: http://unicode-table.com/en/sections/box-drawing/

enter image description here

I believe 192, 195 and 196 are the ones you are after. In Unicode 2501, 2514 and 2523.

EDIT

Found a related stack question here, which recommends printing in Unicode.

What you want is to be able to print unicode, and the answer is in perldoc perluniintro. You can use \x{nnnn} where n is the hex identifier, or you can do \N{...} with the name:

perl -E 'say "\x{2514}"; use charnames; say "\N{BOX DRAWINGS LIGHT UP AND RIGHT}"'
Earl answered 21/2, 2014 at 3:8 Comment(1)
asciitable.com is my favorite website of all timeLounge
F
4
echo -e "\0342\0224\0224\0342\0224\0200\0342\0224\0200 \033[01"
Fed answered 21/2, 2014 at 3:19 Comment(2)
Thanks. This worked for me i got the char '└──'. but how do i print '├── ' ?Washhouse
echo -e "\0342\0224\0234\0342\0224\0200\0342\0224\0200"Fed
E
0

Well, if you landed here, and you just want to display the ascii table like I did at one time, then simply do this:

sudo apt-get update
sudo apt-get install ascii

then:

ascii

This answer my not be directly applicable to the quiz above, but helps those who landed here and were seeking something different like I did one time.

Otherwise, the basic way to see a tree is:

echo -e "\0342\0224\0224\0342\0224\0200\0342\0224\0200 \033[01\ cgi-bin \n|"

Thanks.

Exemplum answered 19/11, 2023 at 6:50 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.