12

I need to combine output of two commands.

For example:

If I input ls -l && file * it will give me

-rw-rw-r-- 1 user user 1356 2012-01-21 07:45 string.c
-rwxrwxr-x 1 user user 7298 2012-01-21 07:32 string_out
-rw-rw-r-- 1 user user  777 2012-01-18 21:44 test

string.c:   ASCII C program text, with CRLF line terminators
string_out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
test:       POSIX shell script text executable

but what I want is:

-rw-rw-r-- 1 user user 1356 2012-01-21 07:45 string.c string.c:   ASCII C program text, with CRLF line terminators
-rwxrwxr-x 1 user user 7298 2012-01-21 07:32 string_out string_out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
-rw-rw-r-- 1 user user  777 2012-01-18 21:44 test test:       POSIX shell script text executable

Any suggestions how to do this?

5 Answers 5

7

Shiplu has a nice simple solution, in bash you can do it without using variables:

for x in *; do 
  echo "$(ls -dl $x) $(file $x)"
done;

Or:

for x in *; do echo "$(ls -dl $x) $(file $x)"; done;

In bash, $(cmd) takes the output of cmd and places it onto the command line, which is very useful for situations like this.

The $() form can be less error prone than using backticks (`cmd`) because it nests safely:

echo $(ls -l $(which bash))

With backticks you have to multiply escape things like quotes

Sign up to request clarification or add additional context in comments.

2 Comments

Nicely done sir! +1, With while loop : while read list && read type <&3; do echo "$list $type"; done < <(tail +2 <(ls -l)) 3< <(file *) though a little cryptic. :)
@JaypalSingh why not you put this as an answer?
5

paste is your friend here. Using bash process substitution:

paste <(ls -l | sed 1d) <(file *)

edit: added sed command to delete first line of ls output ("total: xx")

3 Comments

I like this solution however, since ls -l shows total as the first row, the alignment becomes off i.e first line of output from file * gets displayed next to total.
@jaypal, right but I wouldn't go crazy nesting process substitutions, it really harms readability.
You don't have to use another layer of process substitution, you can do paste <(ls -l | tail -n +2 ) <(file *) instead
1

You can use the join command for this, but it might be tricky to do it all in one command line. If you create two files with the output of each command, it's pretty straightforward. You may need to massage the output a bit (such as removing the trailing : in the output of file).

Comments

1

You need a loop

 for x in *; 
 do 
      ls=`ls -dl $x`
      c=`file $x`
      echo "$ls $c"
 done;

In my Cygwin there is no file command. So I did it with wc. Their output format is almost same.

$ for x in *; do ls=`ls -l $x`; c=`wc -c $x`; echo "$ls : $c"; done;
-rwxr-xr-x 1 shiplu None 18460 Dec 23 16:27 a.exe : 18460 a.exe
-rw-r--r-- 1 shiplu None 340 Dec 23 16:27 tok.c : 340 tok.c

2 Comments

file is available for cygwin, you just have to install it using setup.exe
Thanks for letting me know. In fact I lost my setup.exe. :(
1

Using awk:

awk '
NR==FNR{a[$9":"]=$0;next} 
($1 in a){printf("%-60s\t%-s\n",a[$1],$0)}' <(ls -l) <(file *)

Using while loop (Similar to @Shiplu and @Kyle's answer but using while loop with field descriptors:

while read list && read type <&3; do 
   echo "$list $type"; 
done < <(tail +2 <(ls -l)) 3< <(file *)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.