Overwrite output filename of xgettext - gettext

I am using xgettext with standard input because the input is not available in a file. However, I'd like it to output a filename I specify as a comment above each string.
Current behaviour
#: Standardinput:13
msgid "User"
msgstr ""
#: Standardinput:13
msgid "Invite"
msgstr ""
#: Standardinput:14
msgid "Group"
msgstr ""
Expected behaviour
If I could set a filename to path/to/file.txt, it should output this instead:
#: path/to/file.txt:13
msgid "User"
msgstr ""
#: path/to/file.txt:13
msgid "Invite"
msgstr ""
#: path/to/file.txt:14
msgid "Group"
msgstr ""
I read every option that I can set in the docs and found nothing about it.

The #: path/to/file.txt:14 text is called "location" and the most control you have over this is the --no-location and --add-location flags. See xgettext.c:xgettext_open() for the source code reason why.
Meanwhile, the obvious thing to do is take your input from standard in, pipe the output to standard out, substitute manually, then store in a target PO file. Example:
xgettext -k_ -Lc -o- - < hello.c \
| sed 's##: standard input:##: path/to/file.c:#g' \
> messages.po
Obviously change the patterns inside the sed call to match your xgettext's format and the file you want to represent.
Less obvious is to symlink standard in to a file name that looks like your target. Example:
$ ln -s /dev/stdin file.c
$ echo 'int main() { printf(gettext("Hello World\n")); return 0; }' \
| xgettext --omit-header -o- file.c
#: file.c:1
#, c-format
msgid "Hello World\n"
msgstr ""
Being able to name, for output purposes, the file when input is standard in seems like a reasonable feature. I suggest opening a request at GNU.

Related

Find string tag and replace with a hyperlink using SED

New to SED and trying to use it to find a custom string tag and replace with an html hyperlink, but can't get the following SED format to work correctly. Thanks for your help.
Summary:
Find DEV-XXXX in string and replace w/ an html hyperlink, the DEV- string tag will always remain the same but the XXXX digit reference can vary for different strings.
"This is a test of DEV-1212"
"This is a test of DEV-1213 more text"
Expected results:
"This is a test of DEV-1212"
"This is a test of DEV-1213 more text"
This is the SED syntax I've been working with, but haven't been able to make it work correctly.
$ echo "This is a test DEV-1212" | sed -r 's/DEV-^[^0-9]*([0-9]+).*/&/'
**Produces the following error. **
sed: -e expression #1, char 43: unknown option to `s'
Apart from not escaping the \/ when using / as the delimiter, your pattern does not match because the caret ^ asserts the start of the string which will not match.
DEV-^[^0-9]*([0-9]+).*
----^
If there can only be digits after DEV- you could write the pattern as:
echo "This is a test of DEV-1212" | sed -r 's~DEV-[0-9]+~&~'
Or else keep matching non digits and the rest of the line:
echo "This is a test of DEV-1212" | sed -r 's~DEV-[^0-9]*[0-9].*~&~'
Output
This is a test of DEV-1212
Edit
If you want to match only digits:
echo "This is a test of DEV-1212 with more data" | sed -r 's~DEV-[^0-9]*[0-9]+~&~'
Output
This is a test of DEV-1212 with more data
You did not escape /. Why escape ".
echo "This is a test DEV-1212" | sed -r 's/DEV-^[^0-9]*([0-9]+).*/<a href="https:\/\/devtest.net\/&">&<\/a>/'
but use a different delimieter:
echo "This is a test DEV-1212" | sed -r 's|DEV-^[^0-9]*([0-9]+).*|&|'

Failed to open the file

I am trying to figure out the picture date of files in a folder structure. Some of the folder names contain with whitespaces. Now I try to set the quotes, but it doesn't work.
Can anyone give me a hint?
find . -name "*.jpg" -or -name "*.JPG" >> files.txt
sed -e "s/\(.*\)/'\1'/" files.txt >> files2.txt
for fn in `cat files2.txt`; do
DATEI=$( echo "$fn" | cut -c 3-)
EXIF=$(/usr/bin/exiv2 -pa --grep DateTimeOriginal "'"$PWD$DATEI | awk -F" " '{print $4","$5}')
if [ -z "$EXIF" ]
then
:
else
echo "$PWD$DATEI,$EXIF" >> ausgabe.csv
fi
done
echo "DONE!"
EDIT: This is the output that I get:
'/volume1/Intern/path/to/images/IMG_4206.jpg': Failed to open the file
I take it your result is supposed to look like
"/path/to/photo1.jpg","2017:01:15","22:19:15"
"/path/to/another/photo.JPG","2017:01:15","22:10:01"
The absolute path to the photo, then the DateTimeOriginal date/time, all in quotes.
exiv2 can actually take multiple photos in the file argument, so the whole process can be simplified to a pipeline of two commands:
# Need this for the fileglob
shopt -s globstar extglob
exiv2 -pa -g DateTimeOriginal **/*.#(jpg|JPG) |
awk -v pwd="$PWD/" -v dq='"' -v OFS=',' '{
fn = substr($0, 1, match($0, / *Exif\.Photo/)-1)
print dq pwd fn dq, dq $(NF-1) dq, dq $NF dq
}'
The shell options, globstar and extglob, enable the **/*.*#(jpg|JPG) expression, which returns all files ending in jpg or JPG for the whole directory tree.
exiv2 returns only something for the files that contain DateTimeOriginal data. The intermediate output looks something like this (some whitespace removed):
dir1/photo1.jpg Exif.Photo.DateTimeOriginal Ascii 20 2017:01:22 10:20:36
dir1/photo3.jpg Exif.Photo.DateTimeOriginal Ascii 20 2017:01:22 10:20:36
dir with space/photo2.JPG Exif.Photo.DateTimeOriginal Ascii 20 2017:01:22 10:20:38
dir with space/photo4.JPG Exif.Photo.DateTimeOriginal Ascii 20 2017:01:22 10:40:09
photo5.jpg Exif.Photo.DateTimeOriginal Ascii 20 2017:01:24 20:06:38
photo6.JPG Exif.Photo.DateTimeOriginal Ascii 20 2017:01:22 10:00:55
This would be straightforward with awk, were it not for the paths with spaces as mentioned in the question. The exiv2 output is space separated, and there doesn't seem to be an option to get tabs, so some awk trickery is required:
The path of the current directory, followed by a slash, is passed into the command using -v pwd="$PWD/".
To avoid messy escaping, we define the double quote with -v dq='"'.
The output field separator is set to a comma with -v OFS=','.
To get the filename, we search for the index of a series of spaces followed by Exif.Photo, then we assign a substring that ends just before that index to fn.
To print quoted and comma separated, we use our dq variable, prepend the filename with the path from pwd, and use $(NF-1) and $NF to get the second to last and last field, respectively.
The result is something like
"/home/benjamin/tinker/space dir/dir1/photo1.jpg","2017:01:22","10:20:36"
"/home/benjamin/tinker/space dir/dir1/photo3.jpg","2017:01:22","10:20:36"
"/home/benjamin/tinker/space dir/dir with space/photo2.JPG","2017:01:22","10:20:38"
"/home/benjamin/tinker/space dir/dir with space/photo4.JPG","2017:01:22","10:40:09"
"/home/benjamin/tinker/space dir/photo5.jpg","2017:01:24","20:06:38"
"/home/benjamin/tinker/space dir/photo6.JPG","2017:01:22","10:00:55"
To get this into a file, a redirection > ausgabe.csv has to be appended to the command.
As for why your command didn't work: let's look at a single file as an example. After the sed step, you have something like './photo5.jpg'. Now, you use cut -c 3-, which gives you /photo5.jpg'.
In your EXIF line, you add another single quote, so now exiv2 is looking for a file literally called '/photo5.jpg', including the single quotes – which doesn't exist.

posix shell: reading entries with spaces from a textfile into variables

I want to pass around (lots of) information between scripts, ideally having in- /output of a script persistent.
Using simple textfiles seems rather fitting, but problems arise as soon as entries have spaces.
Whats the preferable way of storing variables in one shell script and reading them in another?
In the examples below I expect the output to be
'publicname' 'x86' '"test directory"' '5' rem:'some other parameters in the future'
Version 1:
This would be my prefered format of the textfile, no escaping necessary, spaces would be entered within quotes.
echo 'publicname x86 "test directory" 5 some other parameters in the future
' >/tmp/input.txt
while read -r name archname vcdir rev rem; do
set -e
[ -n "$name" -a "$name" != "#" ] || continue
echo "'$name' '$archname' '$vcdir' '$rev' rem:'$rem'"
done < /tmp/input.txt
Outputs
'publicname' 'x86' '"test' 'directory"' rem:'5 some other parameters in the future'
Version 2:
Produces correct output, put the input needs to be escaped for the shell. This is problematic since ideally the input would be used with other languages, and be generated by shell scripts too (need to escape variables for export)
echo 'publicname x86 test\ directory 5 some other parameters in the future
' >/tmp/input.txt
while read name archname vcdir rev rem; do
set -e
[ -n "$name" -a "$name" != "#" ] || continue
echo "'$name' '$archname' '$vcdir' '$rev' rem:'$rem'"
done < /tmp/input.txt
The general rule is: use a delimiter that can't appear in a field. Let's say a comma is safe:
echo 'publicname,x86,test directory,5,some other parameters in the future' > /tmp/input.txt
while IFS=, read -r name archname vcdir rev rem; do
printf "'%s' '%s' '%s' '%s' rem:'%s'\n" "$name" "$archname" "$vcdir" "$rev" "$rem"
done < /tmp/input.txt
If a comma could appear in a field, you might want to try a less-common delimiter, such as an ASCII control character.
printf 'publicname\037x86\037test directory\0375\037some other parameters in the future\n' > /tmp/input.txt
while IFS=$(printf '\037') read -r name archname vcdir rev rem; do
printf "'%s' '%s' '%s' '%s' rem:'%s'\n" "$name" "$archname" "$vcdir" "$rev" "$rem"
done < /tmp/input.txt
A simpler alternative is to use a newline, then call read multiple times.
printf 'publicname\nx86\ntest directory\n5\nsome other parameters in the future\n' > /tmp/input.txt
while read -r name; read -r archname; read -r vcdir; read -r rev; read -r rem; do
printf "'%s' '%s' '%s' '%s' rem:'%s'\n" "$name" "$archname" "$vcdir" "$rev" "$rem"
done < /tmp/input.txt
As a last resort, you can try using the null character as the delimiter. [No example, because I am blanking on how to handle null-delimited data in Posix shell, but if you've gotten this far without a feasible solution, shell is probably not the right language to be using.]

sed does not print line when using address format

sed does not print line 1 to line 545.The result of the following command is empty resultfile.txt. Can someone say what should be the correct command?
RESULT=545;sed -n '1, $RESULT p' Configuration.txt > resultfile.txt
The above is not a sed issue, but rather a shell issue: you used single quotes, which inhibit variable expansion.
$ echo '$PWD'
$PWD
$ echo $PWD
/tmp
$ echo "$PWD"
/tmp
Either no quotes at all, or double quotes, allows the shell to expand variables. (No quotes at all means the shell expands everything; double quotes inhibit globbing, redirections, and such.)
Use double quotes so that $RESULT is expanded:
RESULT=545;sed -n "1, $RESULT p" Configuration.txt > resultfile.txt
By the way, the following would be simpler:
head -$RESULT Configuration.txt > resultfile.txt
And, if your file is big, this will quit as soon as you reach line 545 and be more efficient:
sed ${RESULT}q Configuration.txt > resultfile.txt

What is the purpose of the "-" in sh script line: ext="$(echo $ext | sed 's/\./\\./' -)"

I am porting a sh script that was apparently written using GNU implementation of sed to BSD implementation of sed. The exact line in the script with the original comment are:
# escape dot in file extension to grep it
ext="$(echo $ext | sed 's/\./\\./' -)"
I am able to reproduce a results with the following (obviously I am not exhausting all possibilities values for ext) :
ext=.h; ext="$(echo $ext | sed 's/\./\\./' -)"; echo [$ext]
Using GNU's implementation of sed the following is returned:
[\.h]
Using BSD's implementation of sed the following is returned:
sed: -: No such file or directory
[]
Executing ext=.h; ext="$(echo $ext | sed 's/\./\\./')"; echo [$ext] returns [\.h] for both implementation of sed.
I have looked at both GNU and BSD's sed's man page have not found anything about the trailing "-". Googling for sed with a "-" is not very fruitful either.
Is the "-" a typo?
Is the "-" needed for some an unexpected value of $ext?
Is the issue not with sed, but rather with sh?
Can someone direct me to what I should be looking at, or even better, explain what the purpose of the "-" is?
On my system, that syntax isn't documented in the man page, but it is in the
'info' page:
sed OPTIONS... [SCRIPT] [INPUTFILE...]
If you do not specify INPUTFILE, or if INPUTFILE is -',sed'
filters the contents of the standard input.
Given that particular usage, I think you could leave off the '-' and it should
still work.
You got your specific question answered BUT your script is all wrong. Take a look at this:
# escape dot in file extension to grep it
ext="$(echo $ext | sed 's/\./\\./')"
The main problems with that are:
You're not quoting your variable ($ext) so it will go through file name expansion plus if it contains spaces will be passed to echo as multiple arguments instead of 1. Do this instead:
ext="$(echo "$ext" | sed 's/\./\\./')"
You're using an external command (sed) and a pipe to do something the shell can do trivially itself. Do this instead:
ext="${ext/./\.}"
Worst of all: You're escaping the RE meta-character (.) in your variable so you can pass it to grep to do an RE search on it as if it were a string - that doesn't make any sense and becomes intractable in the general case where your variable could contain any combination of RE metacharacters. Just do a string search instead of an RE search and you don't need to escape anything. Don't do either of the above substitution commands and then do either of these instead of grep "$ext" file:
grep -F "$ext" file
fgrep "$ext" file
awk -v ext="$ext" 'index($0,ext)' file